问题描述
我有一个小项目——WinForms 在 .net 框架上 - 只是一个小测试:
private async Task<string> GetTitleAsync()
{
await Task.Delay(3000).ConfigureAwait(false);
return "Hello!";
}
当我运行应用程序时, 单击按钮:“button9” - 导致死锁, (因为线程挂在“.result”上)
以这种方式编写 GetTitleAsync():
${DOCKER_MACHINE}" create -d virtualBox --virtualBox-no-vtx-check $PROXY_ENV "${VM}
解决了死锁 - 应用程序运行正常。
但我不明白怎么做?
我曾预料到,使用“.ConfigureAwait(false)”会导致 情况:
"button9.Text = text;"在不同的线程上执行 在其上创建 UI 的那个, 并且会抛出异常!
但效果很好! 怎么样??
解决方法
我曾预料到,使用“.ConfigureAwait(false)”会导致“button9.Text = text;”的情况在与创建 UI 的线程不同的线程上执行,并且会抛出异常!但效果很好!怎么样??
我推荐阅读我的async
/await
intro;我尽量包括您需要了解的有关 async
/await
及其上下文的所有信息,但不会在介绍中过多详细介绍。
具体来说,该帖子有两点值得注意:
- 每个
async
方法都开始在调用线程上同步执行。 -
await
捕获上下文,除非您使用ConfigureAwait(false)
。
所以,通过这段代码:
private void button9_Click(object sender,EventArgs e)
{
string text = GetTitleAsync().Result;
button9.Text = text;
}
private async Task<string> GetTitleAsync()
{
await Task.Delay(3000).ConfigureAwait(false);
return "Hello!";
}
这是按顺序发生的,特别注意哪个线程运行哪个代码:
-
button9_Click
在 UI 线程上调用GetTitleAsync()
。 -
GetTitleAsync()
调用Task.Delay(3000)
并取回将在 3 秒内完成的任务。 -
GetTitleAsync()
调用ConfigureAwait(false)
并取回不会在当前 (UI) 上下文中恢复的已配置等待器。 -
GetTitleAsync()
使用await
异步等待任务完成。此await
不会在当前 (UI) 上下文中恢复,因为await
已配置为不恢复。 -
await
检查任务并发现它未完成,因此它向调用者返回一个未完成的Task<string>
。 -
button9_Click
在该任务上调用.Result
。这会阻塞 UI 线程,直到该任务完成(即GetTitleAsync()
已完成执行)。 - 三秒后,
Task.Delay(3000)
返回的任务完成。 -
GetTitleAsync()
在其await
之后继续执行。由于这是一个配置的await
,它会继续在线程池线程上执行。 -
GetTitleAsync()
返回"Hello!"
。这是在线程池线程上完成的。 - 通过返回一个值,
GetTitleAsync()
现在已经完成,它之前返回的Task<string>
现在已经完成并带有结果值。此完成也发生在线程池线程上。 - 既然任务现在已经完成,UI 线程不再被阻塞,而是继续执行
button9_Click
。 -
button9_Click
在 UI 线程上执行button9.Text = text;
。