[英]One-line async method SynchronizationContext
I prepared WinForms application to test if a one-line async method would cause a deadlock. 我准备了WinForms应用程序,以测试单行异步方法是否会导致死锁。 button1_Click
event waits for GetZero
task awaited by one-line async proxy method. button1_Click
事件等待单行异步代理方法等待的GetZero
任务。 However, it causes deadlock. 但是,它导致死锁。 Why? 为什么? I've read that one-line async method do not need to continue anything after await
completes, so there is no delegate to post to message pump causing deadlock. 我已经读过,单行异步方法不需要在await
完成后继续执行任何操作,因此没有委托可以将消息发送到导致死锁的消息泵。
For reference, button2_Click
event waits for the result of task GetZero
without proxy caller, and application works fine. 作为参考, button2_Click
事件在没有代理调用方的情况下等待任务GetZero
的结果,并且应用程序可以正常工作。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var zero = ProxyCallery().Result;
label1.Text += $"{zero}";
}
private void button2_Click(object sender, EventArgs e)
{
var zero = GetZero().Result;
label1.Text += $"{zero}";
}
private async Task<int> ProxyCallery()
{
return await GetZero();
}
private async Task<int> GetZero()
{
await Task.Delay(100).ConfigureAwait(false);
return await Task.FromResult(0);
}
}
Why is button1_Click
causing deadlock? 为什么button1_Click
导致死锁?
await Task.Delay(100).ConfigureAwait(false);
configures the await only for that call. 只为该呼叫配置等待。 It doesn't affect awaits that might depend on that particular one, such as the await GetZero()
in the ProxyCallery()
method. 它不会影响可能依赖于该特定await GetZero()
,例如ProxyCallery()
方法中的ProxyCallery()
。
That latter await is still going to require continuation in the UI thread, which you've blocked with ProxyCallery().Result
. 后一种等待仍然需要UI线程中的继续,您已使用ProxyCallery().Result
阻止了该线程。 Hence the deadlock. 因此陷入僵局。
I've read that one-line async method do not need to continue anything after await completes, so there is no delegate to post to message pump causing deadlock. 我已经读过,单行异步方法不需要在等待完成后继续执行任何操作,因此没有委托可以将消息发送到导致死锁的消息泵。
I don't know where you've read that, but it's false. 我不知道你在哪里读的书,但这是错误的。 The compiler doesn't try to optimize "tail awaits". 编译器不会尝试优化“ tail awaits”。 In reality, even if the last thing in the method is an await
, there is still code to be executed on the continuation. 实际上,即使方法中的最后一件事是await
,仍然有继续执行的代码。 At the very least, unwrapping any exception, but also propagating the continuation to the Task
represented by that async
method. 至少,解开任何异常,还要将延续传播到该async
方法表示的Task
。
So there is no difference at all with respect to deadlock potential, or any other aspect of asynchronous execution, for await
statements that conclude a method as compared to await
statements found anywhere else in a method. 因此,对于断定方法的await
语句,与在方法的其他任何地方找到的await
语句相比, await
死锁或异步执行的任何其他方面完全没有区别。
Your ProxyCallery
is actually two lines, in the sense that there is a continuation after the async operation: 您的ProxyCallery
实际上是两行,就异步操作之后的意义而言, 是连续的:
private async Task<int> ProxyCallery()
{
var zero = await GetZero();
return zero; // <-- continuation!
}
The continuation is to return the task's result ! 继续是返回任务的结果 !
Currently, the above continuation is not in the same synchronisation context as the continuation to the Task.Delay
task, which is what causes the deadlock. 当前,上述延续与Task.Delay
任务的延续不在同一同步上下文中,这是导致死锁的原因。
Every task you create should be in the same synchronisation context! 您创建的每个任务都应在相同的同步上下文中!
private async Task<int> ProxyCallery()
{
var zero = await GetZero().ConfigureAwait(false);
return zero;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.