我有一个定义为
的方法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
的分配处放置断点,它永远不会被击中。
我可以补充说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";
}
修改
我尝试删除await Task.Run
以外的所有内容,但它不会改变任何内容。它仍然没有完成。
该应用程序是一个WPF应用程序。调用者线程是UI线程。
我在这里缺少什么?
答案 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