Async-Await在预期的线程上没有执行

时间:2016-05-22 14:38:41

标签: c# async-await

为了理解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。

我知道我必须在这里遗漏一些非常基本的东西,但有人可以帮我理解发生的事情吗?

3 个答案:

答案 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线程池的抽象。一个线程可以开始执行代码,等待未完成的任务,并从不同的线程恢复。

通过这种方式,您可以最大限度地利用CPU而不会阻塞。线程对任务没有意义。等待完成后,可用线程将继续执行任务。它可能是过去执行任务的线程,也可能不是。

答案 2 :(得分:-1)

更改ConfigureAwait(false);到ConfigureAwait(true);或者只是删除它。