将异步/等待与结果混合 [英] Mixing async/await with Result
问题描述
让我以几句话开头这个问题:
Let me just preface this question with a few things:
- 我已经阅读了几个SO问题,要求您不执行此操作(例如异步/等待-异步编程的最佳做法再次说你不应该这样做
- I've read several SO questions saying that you should not do this (such as How to safely mix sync and async code)
- I've read Async/Await - Best Practices in Asynchronous Programming again saying you shouldn't do this
因此,我确实知道这不是最佳做法,也不需要任何人告诉我.这更多是为什么要这样做"的问题.
So I do know that this is not a best practice, and don't need anyone telling me such. This is more of a "why does this work" question.
顺带一提,这是我的问题:
With that out of the way, here is my question:
我编写了一个小型的GUI应用程序,其中包含2个按钮和一个状态标签.其中一个按钮将在100%的时间内通过同步和异步来再现死锁问题.另一个按钮调用相同的异步方法,但它包装在一个Task中,该方法有效.我知道这不是一个好的编码习惯,但是我想了解为什么,它没有相同的死锁问题.这是代码:
I've written a small GUI application that has 2 buttons and a status label. One of the buttons will reproduce the deadlock issue with sync and async 100% of the time. The other button calls the same async method but it is wrapped in a Task, this one works. I know this is not a good coding practice, but I want to understand why it doesn't have the same deadlock issue. Here is the code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async Task<string> DelayAsync()
{
await Task.Delay(1000);
return "Done";
}
private void buttonDeadlock_Click(object sender, EventArgs e)
{
labelStatus.Text = "Status: Running";
// causes a deadlock because of mixing sync and async code
var result = DelayAsync().Result;
// never gets here
labelStatus.Text = "Status: " + result;
}
private void buttonWorking_Click(object sender, EventArgs e)
{
labelStatus.Text = "Status: Running";
string result = null;
// still technically mixes sync and async, but works, why?
result = Task.Run(async () =>
{
return await DelayAsync();
}).Result;
labelStatus.Text = "Status: " + result;
}
}
推荐答案
它之所以有效,是因为buttonWorking_Click
异步代码(DelayAsync
以及传递给Task.Run
的async
lambda)没有当前的SynchronizationContext
,而buttonDeadlock_Click
异步代码(DelayAsync
)可以.您可以通过在调试器中运行并观看SynchronizationContext.Current
来观察差异.
It works because the buttonWorking_Click
async code (DelayAsync
as well as the async
lambda passed to Task.Run
) does not have a current SynchronizationContext
, whereas the buttonDeadlock_Click
async code (DelayAsync
) does. You can observe the difference by running in the debugger and watching SynchronizationContext.Current
.
我会在我的博客文章不要解释死锁情况背后的细节阻止异步代码.
这篇关于将异步/等待与结果混合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!