使用await Task.Run()的Asyc方法永远不会“完成”

时间:2016-01-25 14:38:58

标签: c# asynchronous async-await task-parallel-library

我有一个定义为

的方法
public async Task SomeAsyncMethod()
{
   DoSomeStuff();
   await Task.Run(() => {
     DoSomeSyncStuff();
     DoSomeOtherSyncStuff();
   });
   var someDebugVariable = "someDebugValue";
}

该方法本身正是它应该做的事情,一切运行正常。然而......看起来“外部”异步Task永远不会完成。

示例:我这样称呼它

public void CallerMethod()
{
   Task t = SomeAsyncMethod();
   t.Wait();
}

t.Wait()永远不会完成。此外:如果我在someDebugVariable的分配处放置断点,它永远不会被击中。

我可以补充说DoSomeSyncStuffDoSomeOtherSyncStuff确实做了他们应该做的事情,通过他们调试告诉我他们都完成了。

为证明我的观点,我修改了这样的方法,结果仍然相同。

public async Task SomeAsyncMethod()
{
   DoSomeStuff();
   await Task.Run(() => {
     /*
     DoSomeSyncStuff();
     DoSomeOtherSyncStuff();
     */
     var a = 2; var b = 3; var c = a + b;
   });
   var someDebugVariable = "someDebugValue";
}

修改

我尝试删除await Task.Run以外的所有内容,但它不会改变任何内容。它仍然没有完成。

该应用程序是一个WPF应用程序。调用者线程是UI线程。

我在这里缺少什么?

1 个答案:

答案 0 :(得分:8)

t.Wait()调用导致死锁,并使异步调用完全没有意义。我相信如果您将代码更改为

await Task.Run(() => {
// ...
}).ConfigureAwait(false);

您可以修复死锁并让代码继续,但您应该真正摆脱t.Wait()调用。任何需要完成同步函数调用结果的事情都应该在等待任务之后完成,而不是在调用异步函数之后完成。

更深入: task.Wait()将在任务运行时阻止主线程上的所有执行。当await任务完成时,它会尝试编组回主线程,但是主线程被阻塞了!由于A正在等待B,并且B正在等待A,因此会出现死锁。

请参阅:http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html