为什么在 Windows 服务中阻塞异步会导致死锁?
Why does blocking on async in a Windows Service cause a deadlock?
我的代码中存在死锁问题。
我的代码如下所示:
public async Task DoStuff(input)
{
await AsyncMethod();
//internally calls an async method, and blocks for its return. sometimes couses deadlocks.
new MyService().DoMoreStuff();
}
MyService.DoMoreStuff 实施:
DoMoreStuff()
{
return DoSuffAsyncMethod().Result;
}
此代码有时会使我在 DoSuffAsyncMethod、
上出现死锁
在 MyService.DoMoreStuff 方法中。
但是,如果我将有问题的代码包装在任务中,死锁就不会再发生
public async Task DoStuff(input)
{
await AsyncMethod();
await Task.Run(new MyService().DoMoreStuff());
}
更多信息
此代码在 windows 服务的上下文中运行
因此,不涉及同步上下文。
我知道如何解决这个问题,但仍然不明白为什么代码会死锁。
任何人都可以对没有同步上下文的混合同步异步代码的死锁提出解释吗?
编辑
感谢您的评论。
我假设它死锁了。
实际情况稍微复杂一些,所以我简化了一点。
在 DoSuffAsyncMethod() 中,我们正在调用远程异步服务,经过一些预定义的时间后 - 我们正在超时。
分析请求和接收服务,发现消息确实正确传输。
所以,除了网络或网络框架相关的问题,我们陷入了僵局。
我们假设它是死锁,因为一旦我们重构代码,DoSuffAsyncMethod 中的超时就消失了。
编辑 2
代码
DoSuffAsyncMethod().Wait().Result
错了。
正确的代码是
DoSuffAsyncMethod().Result
问题是由于在调用堆栈的更深处调用了 ConfigureAwait(true)。
感谢您的帮助。
await
基本上意味着:"Hey thread
go on doing your stuff, when I'm ready I'll ask for you to continue my job"。线程就像:"Yes, but I'll come to you when I've completed the rest of my work"。然后你要求线程 Wait
上一个任务,但它永远不会完成工作,因为要完成它需要线程回到他身边(是的,正在等待它的线程......)
但是当你这样做的时候
await Task.Run(new MyService().DoMoreStuff());
await
之后的线程可用于恢复之前等待的任务 (DoMoreStuff()
),因此他们都能够完成工作。
可以找到更多信息,可能还有更好的解释 here
我的代码中存在死锁问题。
我的代码如下所示:
public async Task DoStuff(input)
{
await AsyncMethod();
//internally calls an async method, and blocks for its return. sometimes couses deadlocks.
new MyService().DoMoreStuff();
}
MyService.DoMoreStuff 实施:
DoMoreStuff()
{
return DoSuffAsyncMethod().Result;
}
此代码有时会使我在 DoSuffAsyncMethod、
上出现死锁在 MyService.DoMoreStuff 方法中。
但是,如果我将有问题的代码包装在任务中,死锁就不会再发生
public async Task DoStuff(input)
{
await AsyncMethod();
await Task.Run(new MyService().DoMoreStuff());
}
更多信息
此代码在 windows 服务的上下文中运行 因此,不涉及同步上下文。
我知道如何解决这个问题,但仍然不明白为什么代码会死锁。
任何人都可以对没有同步上下文的混合同步异步代码的死锁提出解释吗?
编辑
感谢您的评论。
我假设它死锁了。
实际情况稍微复杂一些,所以我简化了一点。
在 DoSuffAsyncMethod() 中,我们正在调用远程异步服务,经过一些预定义的时间后 - 我们正在超时。
分析请求和接收服务,发现消息确实正确传输。
所以,除了网络或网络框架相关的问题,我们陷入了僵局。
我们假设它是死锁,因为一旦我们重构代码,DoSuffAsyncMethod 中的超时就消失了。
编辑 2 代码
DoSuffAsyncMethod().Wait().Result
错了。
正确的代码是
DoSuffAsyncMethod().Result
问题是由于在调用堆栈的更深处调用了 ConfigureAwait(true)。
感谢您的帮助。
await
基本上意味着:"Hey thread
go on doing your stuff, when I'm ready I'll ask for you to continue my job"。线程就像:"Yes, but I'll come to you when I've completed the rest of my work"。然后你要求线程 Wait
上一个任务,但它永远不会完成工作,因为要完成它需要线程回到他身边(是的,正在等待它的线程......)
但是当你这样做的时候
await Task.Run(new MyService().DoMoreStuff());
await
之后的线程可用于恢复之前等待的任务 (DoMoreStuff()
),因此他们都能够完成工作。
可以找到更多信息,可能还有更好的解释 here