我想知道使用 TaskCompletitionSource 是否是一个糟糕的选择
I was wondering if using TaskCompletitionSource is a bad choice
我必须在这里补充一点,我不是 Whosebug 上的老练提问者,所以我很高兴收到关于为什么我的问题可能不适合这里的反馈。
包装非异步调用时等待 TaskCompletitionSource 是件坏事吗?
这是我的用例:
我有一个处理程序 class,它会在事件发生时调用函数 Func<T, Task>
回调。处理程序从我的应用程序外部调用并通知我的 UI。
有两种方法 A 和 B 用作回调。 A 调用异步 HTTP 客户端,B 进行计算。在这两种情况下,等待调用都会解冻 UI,然后更新属性。
答:
public async Task A(){
result = await CallHttpClient(...) // unfreeze UI
// ... copy image bytes and update UI (long running not async)
// release bytes in calling method
}
乙:
public async Task B(){
var tcs = new TaskCompletionSource<bool>();
await tcs.Task; // unfreeze UI
// ... copy image bytes and update UI (long running not async)
tcs.SetResult(true); // release bytes in calling method
}
我的问题是,使用 TaskCompletionSource 包装非异步调用是一种不好的做法吗?
文档说明如下。
If you want to create a task wrapper for an existing asynchronous operation or event, use TaskCompletionSource. https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
另一种可能是调用Task.Run(),但我感觉更糟。
不使用 Async 会导致冻结 UI 这不是我真正想要的,尽管它可能是最干净的解决方案。
-------->更新
正如其他人所说,Task.Run() 在这里完全没问题。
我应该注意到我的 B: 看起来不一样了
乙:
public async Task B(...){
var tcs = new TaskCompletionSource<bool>();
// ... duplicate bytes
tcs.SetResult(true); // release bytes in calling method
await tcs.Task; // unfreeze UI
// ... copy image bytes and update UI (long running not async)
}
使用下面的 Task.Run() 找到更好的选择。
我还应该注意,当方法离开时,字节(示例中未显示)被释放。
如果没有某种多线程,就无法在后台执行 CPU 绑定任务。
此代码...
var tcs = new TaskCompletionSource<bool>();
await tcs.Task; // unfreeze UI
// ... copy image bytes and update UI (long running not async)
tcs.SetResult(true); // release bytes in calling method
...将在 await
上阻塞,因为 SetResult
直到之后才被调用,导致某种死锁。
我想你可以做这样疯狂的事情
var tcs = new TaskCompletionSource<bool>();
Parallel.Invoke
(
() => await tcs.Task,
() => {
// ... copy image bytes and update UI (long running not async)
tcs.SetResult(true); // release bytes in calling method
}
);
但我也不确定这是否可行。执行此操作的标准方法是
await Task.Run( () => {
// ... copy image bytes and update UI (long running not async)
});
...这当然更容易理解,并且是 Task.Run()
的意思。
我必须在这里补充一点,我不是 Whosebug 上的老练提问者,所以我很高兴收到关于为什么我的问题可能不适合这里的反馈。
包装非异步调用时等待 TaskCompletitionSource 是件坏事吗?
这是我的用例:
我有一个处理程序 class,它会在事件发生时调用函数 Func<T, Task>
回调。处理程序从我的应用程序外部调用并通知我的 UI。
有两种方法 A 和 B 用作回调。 A 调用异步 HTTP 客户端,B 进行计算。在这两种情况下,等待调用都会解冻 UI,然后更新属性。
答:
public async Task A(){
result = await CallHttpClient(...) // unfreeze UI
// ... copy image bytes and update UI (long running not async)
// release bytes in calling method
}
乙:
public async Task B(){
var tcs = new TaskCompletionSource<bool>();
await tcs.Task; // unfreeze UI
// ... copy image bytes and update UI (long running not async)
tcs.SetResult(true); // release bytes in calling method
}
我的问题是,使用 TaskCompletionSource 包装非异步调用是一种不好的做法吗?
文档说明如下。
If you want to create a task wrapper for an existing asynchronous operation or event, use TaskCompletionSource. https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
另一种可能是调用Task.Run(),但我感觉更糟。 不使用 Async 会导致冻结 UI 这不是我真正想要的,尽管它可能是最干净的解决方案。
-------->更新
正如其他人所说,Task.Run() 在这里完全没问题。
我应该注意到我的 B: 看起来不一样了 乙:
public async Task B(...){
var tcs = new TaskCompletionSource<bool>();
// ... duplicate bytes
tcs.SetResult(true); // release bytes in calling method
await tcs.Task; // unfreeze UI
// ... copy image bytes and update UI (long running not async)
}
使用下面的 Task.Run() 找到更好的选择。
我还应该注意,当方法离开时,字节(示例中未显示)被释放。
如果没有某种多线程,就无法在后台执行 CPU 绑定任务。
此代码...
var tcs = new TaskCompletionSource<bool>();
await tcs.Task; // unfreeze UI
// ... copy image bytes and update UI (long running not async)
tcs.SetResult(true); // release bytes in calling method
...将在 await
上阻塞,因为 SetResult
直到之后才被调用,导致某种死锁。
我想你可以做这样疯狂的事情
var tcs = new TaskCompletionSource<bool>();
Parallel.Invoke
(
() => await tcs.Task,
() => {
// ... copy image bytes and update UI (long running not async)
tcs.SetResult(true); // release bytes in calling method
}
);
但我也不确定这是否可行。执行此操作的标准方法是
await Task.Run( () => {
// ... copy image bytes and update UI (long running not async)
});
...这当然更容易理解,并且是 Task.Run()
的意思。