ConfigureAwait,UI,等待异步
ConfigureAwait , UI, await async
我有一个小项目 - WinForms
在 .net frameWork 上 - 只是一个小测试:
private void button9_Click(object sender, EventArgs e)
{
string text = GetTitleAsync().Result;
button9.Text = text;
}
private async Task<string> GetTitleAsync()
{
await Task.Delay(3000);
return "Hello!";
}
作为我运行的应用程序,
单击按钮:“button9” - 导致死锁,
(因为线程挂在“.result”上)
以这种方式编写 GetTitleAsync():
private async Task<string> GetTitleAsync()
{
await Task.Delay(3000).ConfigureAwait(false);
return "Hello!";
}
解决了死锁 - 并且应用程序 运行 正常。
但是我不明白怎么办?
我原以为使用“.ConfigureAwait(false)”会导致
情况:
"button9.Text = 文本;"在不同的线程上执行
创建 UI 的那个,
并且会抛出异常!
但效果很好!
怎么样??
I would have expected, that using ".ConfigureAwait(false)" would cause a situation in which "button9.Text = text;" is executed on a different thread than the one, on which the UI was created, and an excpetion would be throwed ! but it works excellent ! how??
我建议阅读我的 async
/await
intro;我尽量包含您需要了解的关于 async
/await
及其上下文的所有信息,但不会涉及太多细节以供介绍。
具体来说,post有两点值得注意:
- 每个
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
检查任务并发现它未完成,因此它 returns 未完成 Task<string>
给它的调用者。
button9_Click
在该任务上调用 .Result
。这会阻塞 UI 线程,直到该任务完成(即,GetTitleAsync()
已完成执行)。
- 三秒后,从
Task.Delay(3000)
返回的任务完成。
GetTitleAsync()
在其 await
之后恢复执行。由于这是配置的 await
,它会继续在线程池线程上执行。
GetTitleAsync()
returns"Hello!"
。这是在线程池线程上完成的。
- 通过返回一个值,
GetTitleAsync()
现在完成了,它之前返回的 Task<string>
现在完成了一个结果值。此完成也发生在线程池线程上。
- 由于任务现已完成,UI线程不再阻塞,它继续执行
button9_Click
。
button9_Click
在 UI 线程上执行 button9.Text = text;
。
我有一个小项目 - WinForms 在 .net frameWork 上 - 只是一个小测试:
private void button9_Click(object sender, EventArgs e)
{
string text = GetTitleAsync().Result;
button9.Text = text;
}
private async Task<string> GetTitleAsync()
{
await Task.Delay(3000);
return "Hello!";
}
作为我运行的应用程序, 单击按钮:“button9” - 导致死锁, (因为线程挂在“.result”上)
以这种方式编写 GetTitleAsync():
private async Task<string> GetTitleAsync()
{
await Task.Delay(3000).ConfigureAwait(false);
return "Hello!";
}
解决了死锁 - 并且应用程序 运行 正常。
但是我不明白怎么办?
我原以为使用“.ConfigureAwait(false)”会导致 情况:
"button9.Text = 文本;"在不同的线程上执行 创建 UI 的那个, 并且会抛出异常!
但效果很好! 怎么样??
I would have expected, that using ".ConfigureAwait(false)" would cause a situation in which "button9.Text = text;" is executed on a different thread than the one, on which the UI was created, and an excpetion would be throwed ! but it works excellent ! how??
我建议阅读我的 async
/await
intro;我尽量包含您需要了解的关于 async
/await
及其上下文的所有信息,但不会涉及太多细节以供介绍。
具体来说,post有两点值得注意:
- 每个
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
检查任务并发现它未完成,因此它 returns 未完成Task<string>
给它的调用者。button9_Click
在该任务上调用.Result
。这会阻塞 UI 线程,直到该任务完成(即,GetTitleAsync()
已完成执行)。- 三秒后,从
Task.Delay(3000)
返回的任务完成。 GetTitleAsync()
在其await
之后恢复执行。由于这是配置的await
,它会继续在线程池线程上执行。GetTitleAsync()
returns"Hello!"
。这是在线程池线程上完成的。- 通过返回一个值,
GetTitleAsync()
现在完成了,它之前返回的Task<string>
现在完成了一个结果值。此完成也发生在线程池线程上。 - 由于任务现已完成,UI线程不再阻塞,它继续执行
button9_Click
。 button9_Click
在 UI 线程上执行button9.Text = text;
。