为了理解async / await,我制作了一个带有一个按钮的示例WPF应用程序。点击它会做一些“工作”:
private async void goButtonClicked(object sender, EventArgs e)
{
WhatThreadAmI();
var task = populateRawData().ConfigureAwait(false);
WhatThreadAmI();
BusyIndicator.IsBusy = true;
await task;
WhatThreadAmI(); //this isnt on the main thread - why??
BusyIndicator.IsBusy = false;
Console.WriteLine("fin");
}
“WhatThreadAmI”只是将当前线程与我在初始化时保存的UI线程进行比较。
public bool IsMainThread => uiThread == Thread.CurrentThread;
我希望这个输出为True - True - True,填充原始数据方法中的“WhatThreadAmI”调用返回false。
实际发生的是True - True - False,填充原始数据方法中的“WhatThreadAmI”调用返回true。
我知道我必须在这里遗漏一些非常基本的东西,但有人可以帮我理解发生的事情吗?
答案 0 :(得分:4)
var task = populateRawData().ConfigureAwait(false);
ConfigureAwait(false)
返回已配置的任务awaiter 未在捕获的上下文中恢复。我在博客上详细解释how await
captures and resumes on context; ConfigureAwait(false)
的使用意味着不在上下文中捕获和恢复。在这种情况下,“上下文”是UI线程。因此,await
不会恢复UI线程,因为ConfigureAwait(false)
明确告诉await
它不需要。
在旁注中,该代码中的task
变量不包含Task
。将ConfigureAwait
的结果放在变量而不是await
中是非常不寻常的。以下示例是等效的 - 我认为 - 更清楚地表达了正在发生的事情:
WhatThreadAmI();
var task = populateRawData();
WhatThreadAmI();
BusyIndicator.IsBusy = true;
await task.ConfigureAwait(false);
WhatThreadAmI(); //this isnt on the main thread - why??
BusyIndicator.IsBusy = false;
换句话说:它是ConfigureAwait
,而不是ConfigureTask
。它根本不会改变任务;只有ConfigureAwait
与await
一起使用才有意义。
答案 1 :(得分:0)
Task
对象是.Net线程池的抽象。一个线程可以开始执行代码,等待未完成的任务,并从不同的线程恢复。
答案 2 :(得分:-1)
更改ConfigureAwait(false);到ConfigureAwait(true);或者只是删除它。