C# Task.Run流同步上下文何时与ExecutionContext一起运行?
来自以下状态:C# Task.Run流同步上下文何时与ExecutionContext一起运行?,c#,asynchronous,async-await,synchronizationcontext,C#,Asynchronous,Async Await,Synchronizationcontext,来自以下状态:SynchronizationContext可能与ExecutionContext一起流动: private async void button1_Click(object sender, EventArgs e) { Console.WriteLine("Click context:" + SynchronizationContext.Current); button1.Text = await Task.Run(async delegate {
SynchronizationContext
可能与ExecutionContext
一起流动:
private async void button1_Click(object sender, EventArgs e) {
Console.WriteLine("Click context:" + SynchronizationContext.Current);
button1.Text = await Task.Run(async delegate {
// In my tests this always returns false
Console.WriteLine("SynchronizationContext was flowed: " + (SynchronizationContext.Current != null));
string data = await DownloadAsync();
return Compute(data);
});
}
下面是我的心智模型告诉我的,这个代码会发生什么。A.
用户单击按钮1,导致UI框架调用按钮1\u单击
在UI线程上。然后,代码启动一个工作项以在
线程池(通过Task.Run)。该工作项开始一些下载工作
并异步等待它完成。后续工作项
然后在线程池上对
下载的结果,并返回结果,导致
正在等待UI线程完成。此时,用户界面
线程处理此按钮单击方法的其余部分,存储
将计算结果输入button1的文本属性
如果SynchronizationContext不作为一部分流动,我的期望是有效的
执行上下文。但是,如果它真的流了,我会非常难过
失望。Task.Run在调用时捕获ExecutionContext,并且
使用它运行传递给它的委托。这意味着用户界面
调用Task.Run时当前的SynchronizationContext
将流入任务,并且在调用时是当前的
下载Async并等待生成的任务。那就意味着
等待将看到当前SynchronizationContext并发布
异步方法的剩余部分作为在
用户界面线程。这意味着我的计算方法很可能是
在UI线程上运行,而不是在线程池上运行,导致
我的应用程序的响应问题
故事现在变得有点混乱:ExecutionContext实际上有两种捕获方法,但是
其中只有一个是公开的。内部的一个(mscorlib的内部)
是从中公开的大多数异步功能所使用的
mscorlib,并且它可以选择性地允许调用方抑制
作为ExecutionContext的一部分捕获SynchronizationContext;
与此相对应,还有一个运行的内部过载
方法,该方法支持忽略存储的SynchronizationContext
在行刑的背景下,实际上是假装一个人没有被抓获
(这也是mscorlib中大多数功能所使用的重载)。
这意味着几乎所有异步操作
核心实现驻留在mscorlib中,不会流动
SynchronizationContext作为ExecutionContext的一部分,但任何
其核心实现位于其他任何位置的异步操作
将同步上下文作为ExecutionContext的一部分流动。我
前面提到异步方法的“构建器”是
负责在异步方法中流动ExecutionContext的类型,以及
这些构建器确实生活在mscorlib中,并且使用内部
重载…因此,SynchronizationContext不会作为
跨等待的ExecutionContext(同样,这与任务的方式是分开的)
等待者支持捕获同步上下文和发布
回到它)。帮助处理ExecutionContext无法处理的情况
流同步上下文,异步方法基础结构尝试
忽略由于流动而设置为当前的SynchronizationContext
然而,我并不清楚什么时候会发生这种情况。当使用publicExecutionContext.Capture
方法且未使用内部Task.Run
重载来抑制流动SynchronizationContext
withExecutionContext
时,似乎会发生这种情况,但我不知道何时会发生这种情况
在我对.NET 4.5的测试中,任务.Run
似乎没有将SynchronizationContext
与ExecutionContext
流动:
private async void button1_Click(object sender, EventArgs e) {
Console.WriteLine("Click context:" + SynchronizationContext.Current);
button1.Text = await Task.Run(async delegate {
// In my tests this always returns false
Console.WriteLine("SynchronizationContext was flowed: " + (SynchronizationContext.Current != null));
string data = await DownloadAsync();
return Compute(data);
});
}
所以我的问题是,在什么情况下,Compute()
Task.Run流同步上下文何时与ExecutionContext一起运行
从来没有
那篇文章的要点是(用于)流动ExecutionContext
的公共API将流动SynchronizationContext
。但是Task.Run
(以及“几乎所有核心实现驻留在mscorlib中的异步操作”)永远不会这样做
以“如果”开头的段落是假设性的。他描述了如果Task.Run
使用公共API流动ExecutionContext
会发生什么。如果它这样做的话,就会产生问题。这就是为什么它从来没有这样做过