简体   繁体   English

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

[英]Async-Await Not Executing On Expected Thread

In an attempt to understand async/await I made a little sample WPF application that has one button. 为了理解async / await,我做了一个带有一个按钮的示例WPF应用程序。 When clicked it will do some 'work' : 点击它会做一些“工作”:

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");
        }

The "WhatThreadAmI" simply compares the current thread to the UI thread which I save on initialization. “WhatThreadAmI”只是将当前线程与我在初始化时保存的UI线程进行比较。

public bool IsMainThread => uiThread == Thread.CurrentThread;

I expected the output of this to be True - True - True, with the "WhatThreadAmI" call in the populate raw data method to return false. 我希望它的输出为True - True - True,填充原始数据方法中的“WhatThreadAmI”调用返回false。

What actually happens is True - True - False, with the ""WhatThreadAmI" call in the populate raw data method returning true. 实际发生的是True - True - False,填充原始数据方法中的“”WhatThreadAmI“调用返回true。

I know I must be missing something very fundamental here, but can someone please help me understand what is going on? 我知道我必须在这里遗漏一些非常基本的东西,但有人可以帮我理解发生了什么吗?

var task = populateRawData().ConfigureAwait(false);

ConfigureAwait(false) returns a configured task awaiter that does not resume on a captured context . ConfigureAwait(false)返回未在捕获的上下文上恢复的已配置任务awaiter。 I explain how await captures and resumes on context in detail on my blog; 我将解释如何await捕捉和恢复的情况下在我的博客上详细; the usage of ConfigureAwait(false) means to not capture and resume on the context. ConfigureAwait(false)的用法意味着捕获和恢复上下文。 In this case, the "context" is the UI thread. 在这种情况下,“上下文”是UI线程。 So, the await doesn't resume of the UI thread because the ConfigureAwait(false) is explicitly telling the await that it doesn't need to. 因此, await不会恢复UI线程,因为ConfigureAwait(false)明确告诉await它不需要。

On a side note, the task variable in that code does not contain a Task . 另外,该代码中的task变量包含Task It's extremely unusual to have the result of ConfigureAwait in a variable instead of with its await . ConfigureAwait的结果放在变量而不是await是极其罕见的。 The following example is equivalent and - I think - expresses more clearly what's going on: 以下示例是等效的 - 我认为 - 更清楚地表达了正在发生的事情:

WhatThreadAmI();
var task = populateRawData();
WhatThreadAmI();
BusyIndicator.IsBusy = true;    

await task.ConfigureAwait(false);
WhatThreadAmI(); //this isnt on the main thread - why??
BusyIndicator.IsBusy = false;

Put another way: it's ConfigureAwait , not ConfigureTask . 换句话说:它是ConfigureAwait ,而不是ConfigureTask It doesn't change the task at all; 它根本不会改变任务; ConfigureAwait only makes sense to use with await . ConfigureAwait 仅适用await

the Task object is an abstraction over the .Net Thread pool. Task对象是.Net线程池的抽象。 one thread may begin executing code, await a not-finished task, and be resumed from a different thread. 一个线程可以开始执行代码,等待未完成的任务,并从不同的线程恢复。

in this way you can maximize the use of your CPU without blocking. 通过这种方式,您可以最大限度地利用CPU而不会阻塞。 threads have no meaning to tasks. 线程对任务没有意义。 an available thread will continue your task execution when awaiting is finished. 等待完成后,可用线程将继续执行任务。 it may be the thread which executed the task in the past, it may not. 它可能是过去执行任务的线程,也可能不是。

change ConfigureAwait(false); 更改ConfigureAwait(false); to ConfigureAwait(true); 到ConfigureAwait(true); or just remove it. 或者只是删除它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM