我必须在这里补充一下,我不是Stackoverflow上的练习提问者,所以我很高兴收到有关为什么我的问题可能不适合这里的反馈。
包装一个非异步调用时,等待TaskCompletitionSource是一件坏事吗?
这是我的用例:
我有一个处理程序类,它Func<T, Task>
在事件发生时调用函数回调。从我的应用程序外部调用该处理程序,并通知我的UI。有两种方法A和B用作回调。A在这里调用异步HTTP客户端,B在这里进行计算。在这两种情况下,等待调用都将解冻UI,然后更新属性。
A:
public async Task A(){
result = await CallHttpClient(...) // unfreeze UI
// ... copy image bytes and update UI (long running not async)
// release bytes in calling method
}
B:
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
}
My question here, is it a bad practice to use TaskCompletionSource to wrap a not async call?
The Documentation states the following.
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
Another possibility is to call Task.Run(), but it feels even worse to me. Not using Async would result in a freezing UI which is not really what I want although it might be the cleanest solution.
-------> Update
As state by others the Task.Run() is perfectly fine here.
I should note that my B: look different 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)
}
Find better option with Task.Run() below.
I should also note that when the method leaves the bytes (not shown in the example) are released.
如果没有某种多线程,就无法在后台执行与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()
是要这样做的。
你是对的,我可以使用Task.Run()。调用Task.Run()会很好。我应该写过tcs.SetResult(true); 在等待之前。