我必须在这里补充一下,我不是Stackoverflow的实践提问者,因此,我很高兴收到有关为何我的问题可能不适合此处的反馈。
等待TaskCompletitionSource不好做吗?
这是我的用例:
我有一个处理程序类,该类在事件发生时调用函数Func<T, Task>
回调。有两种方法A和B用作回调。 A在这里调用异步HTTP客户端,B在这里进行计算。在这两种情况下,await调用都会解冻UI,然后更新属性。
A:
result = await CallHttpClient(...) // unfreeze UI
// ... copy image bytes and update UI (long running not async)
// release bytes in calling method
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封装非异步调用是否是一种不好的做法?
该文档规定以下内容。
如果要为现有的异步操作或事件创建任务包装,请使用TaskCompletionSource。 https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
另一种可能性是调用Task.Run(),但对我来说感觉更糟。不使用Async会导致UI冻结,虽然这可能是最干净的解决方案,但这并不是我真正想要的UI。
[如果没有某种多线程,就无法在后台执行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()
。