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

Hem*_*era 6 c# asynchronous task-parallel-library async-await

我有一个定义为的方法

public async Task SomeAsyncMethod()
{
   DoSomeStuff();
   await Task.Run(() => {
     DoSomeSyncStuff();
     DoSomeOtherSyncStuff();
   });
   var someDebugVariable = "someDebugValue";
}
Run Code Online (Sandbox Code Playgroud)

该方法本身正是它应该做的事情,一切运行正常.然而......看起来"外部"异步Task从未完成.

示例:当我这样称呼它时

public void CallerMethod()
{
   Task t = SomeAsyncMethod();
   t.Wait();
}
Run Code Online (Sandbox Code Playgroud)

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

我可能会添加它DoSomeSyncStuff并且DoSomeOtherSyncStuff真正做他们应该做的事情并通过它们调试告诉我他们都完成了.

为了证明我的观点,我修改了这样的方法,结果仍然是一样的.

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

编辑

我已经尝试删除除了await Task.Run它之外的一切,它不会改变任何东西.它仍然没有完成.

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

我在这里错过了什么?

Ste*_*eve 10

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

await Task.Run(() => {
// ...
}).ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)

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

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

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