2016-05-22 45 views
3

在试图理解异步/等待我做了一个示例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; 

我预计这个输出是真 - 真 - 真,随着填入原始数据法“WhatThreadAmI”调用返回false。

实际发生什么是真正的 - 真 - 假,随着填入原始数据法“” WhatThreadAmI”调用返回true

我知道我必须在这里失去了一些非常基本的,但有人请帮助。我明白了是怎么回事?

+0

[异步不是线程](http://stackoverflow.com/q/17661428/11683)。 – GSerg

+3

即使是这样,当您创建任务时,确实会说'.ConfigureAwait(false)',这意味着“我不需要在原始上下文中恢复”。只要你“等待”那个任务,你的环境就会改变,所以在这里就不足为奇了。当你简单地创建任务但不等待它时,上下文不会改变,所以两个第一个'WhatThreadAmI'返回'true'。 – GSerg

+0

有道理 - 谢谢! – smodle

回答

0

Task对象是在.NET线程池的抽象。一个线程可以开始执行代码,等待一个不完成任务,并从不同的线程恢复。

通过这种方式,您可以最大限度地利用您的CPU而不会阻塞o意味着任务。一个可用的线程将在等待完成时继续执行任务。它可能是过去执行任务的线程,它可能不是。

+1

我喜欢这个答案,因为它是问题中隐含的关键细节的核心。如果您依赖特定线程的某些行为,那么Async Await不是您的解决方案。我将Async Await描述为“如果可以,请尝试并行化”。 “随机”使用线程。这里有一个设计和体系结构的细节,如果你试图去理解它,这并不是微不足道的。如果你想了解原始问题是一个很好的问题。为什么它在所有环境中都不会如预期那样是一个很好的例子,原来的问题已经浮出水面。 –

+0

感谢您的扩展,我同意 - 我从根本上误解了Async/Await的功能,并且此答案确实解决了最初的问题。 – smodle

-1

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

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