使用 await Task.Run() 的异步方法从不 "completes"

Asyc method using await Task.Run() never "completes"

我有一个定义为

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

该方法本身完全按照它应该做的去做,一切运行良好。然而...看起来 "outer" 异步 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 线程。

我在这里错过了什么?

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