[英]Task's continuation (built by async/await) is running on main thread in a WPF application, but on child in a console application
Assume I have a simple C#
Console Application: 假设我有一个简单的
C#
控制台应用程序:
class Program
{
static async void func()
{
Thread.CurrentThread.Name = "main";
await Task.Run(() =>
{
Thread.CurrentThread.Name = "child";
Thread.Sleep(5000);
});
Console.WriteLine("continuation is running on {0} thread", Thread.CurrentThread.Name);
}
static void Main(string[] args)
{
func();
Thread.Sleep(10000);
}
}
When 5000 ms pass, we see the "continuation is running on child thread" message. 经过5000毫秒后,我们看到“继续在子线程上运行”消息。 When another 5000 ms pass, main thread finishes its work and application is closed.
当又经过5000毫秒时,主线程完成其工作,并且应用程序关闭。 It looks rather logical: asynchronous task and its continuation are running on the same child thread.
它看起来很合乎逻辑:异步任务及其延续在同一子线程上运行。
But assume now I have a simple WPF
application: 但假设现在我有一个简单的
WPF
应用程序:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
async private void mainWnd_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Thread.CurrentThread.Name = "main";
await Task.Run(() =>
{
Thread.CurrentThread.Name = "child";
Thread.Sleep(5000);
});
this.Title = string.Format("continuation is running on {0} thread", Thread.CurrentThread.Name);
}
private void mainWnd_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
Thread.Sleep(10000);
}
}
Now when we press left mouse button and 5000 ms pass, we see "continuation is running on main thread" title. 现在,当我们按下鼠标左键并经过5000毫秒时,我们看到“继续在主线程上运行”标题。 Moreover, if we press left button and then right button, application first will run
mainWnd_MouseLeftButtonDown
handler, then mainWnd_MouseRightButtonDown
handler (on main thread), main thread will sleep for 10000 ms, and then continuation of asynchronous task from mainWnd_MouseLeftButtonDown
will be still performed on main thread. 此外,如果我们按下左键,然后右键,应用程序第一次运行
mainWnd_MouseLeftButtonDown
处理程序,然后mainWnd_MouseRightButtonDown
处理程序(在主线程),主线程会睡眠10000毫秒,然后从异步任务的延续mainWnd_MouseLeftButtonDown
将在主来仍然执行线。
Why does async-await
mechanism differ for these two situations? 为什么这两种情况的
async-await
机制不同?
I know that in WPF
method can be explicitly run on UI thread through Dispatcher.Invoke
, but async-await
mechanism isn't WPF
-specific, so its behavior should be equal in any kind of application, shouldn't it? 我知道可以通过
Dispatcher.Invoke
在WPF
中显式地在UI线程上运行方法,但是async-await
机制不是特定于WPF
,因此它的行为在任何类型的应用程序中都应该相等,不是吗?
Any help will be appreciated. 任何帮助将不胜感激。
async-await
respects the current scope's SynchronizationContext
. async-await
尊重当前范围的SynchronizationContext
。 That means that the context (if it exists) is captured when the asynchronous operation starts and when it ends the continuation is scheduled on the captured context. 这意味着在异步操作开始时捕获上下文(如果存在),并在结束时在捕获的上下文上调度继续。
UI
applications ( WPF
/ Winforms
) use a SynchronizationContext
that allows only for the main ( UI
) thread to interact with the UI
elements, so it seamlessly works with async-await
. UI
应用程序( WPF
/ Winforms
)使用SynchronizationContext
,它仅允许主( UI
)线程与UI
元素进行交互,因此它可以与async-await
无缝async-await
。
ASP.Net
also has it's own SynchronizationContext
called AspNetSynchronizationContext
(surprisingly). ASP.Net
也有自己的SynchronizationContext
称为AspNetSynchronizationContext
(令人惊讶)。 So it isn't necessarily about UI
or Single Thread Apartments . 因此,它不一定与
UI
或Single Thread Apartments有关 。
If you want to disable that useful SynchronizationContext
capturing you just need to use ConfigureAwait
: 如果要禁用有用的
SynchronizationContext
捕获,则只需使用ConfigureAwait
:
await Task.Run(() =>
{
Thread.CurrentThread.Name = "child";
Thread.Sleep(5000);
}).ConfigureAwait(false);
More on SynchronizationContexts: It's All About the SynchronizationContext 有关SynchronizationContext的更多信息: 一切都与SynchronizationContext有关
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.