温馨提示:本文翻译自stackoverflow.com,查看原文请点击:c# - I was wondering if using TaskCompletitionSource is a bad choice
.net c# task-parallel-library taskcompletionsource

c# - 我想知道是否使用TaskCompletitionSource是一个错误的选择

发布于 2020-03-28 23:32:39

我必须在这里补充一下,我不是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.

查看更多

查看更多

提问者
Dr.Bob
被浏览
134
John Wu 2020-01-31 17:46

如果没有某种多线程,就无法在后台执行与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()是要这样做的。