gpt4 book ai didi

c# - Task.Run 什么时候流 SynchronizationContext 和 ExecutionContext?

转载 作者:行者123 更新时间:2023-11-30 20:01:05 27 4
gpt4 key购买 nike

This article来自 SynchronizationContext 可能与 ExecutionContext 一起流动的状态:

private void button1_Click(object sender, EventArgs e)  { 
button1.Text = await Task.Run(async delegate
{
string data = await DownloadAsync();
return Compute(data);
});
}

Here’s what my mental model tells me will happen with this code. A user clicks button1, causing the UI framework to invoke button1_Click on the UI thread. The code then kicks off a work item to run on the ThreadPool (via Task.Run). That work item starts some download work and asynchronously waits for it to complete. A subsequent work item on the ThreadPool then does some compute-intensive operation on the result of that download, and returns the result, causing the Task that was being awaited on the UI thread to complete. At that point, the UI thread processes the remainder of this button1_Click method, storing the result of the computation into the button1’s Text property.

My expectation is valid if SynchronizationContext doesn’t flow as part of ExecutionContext. If it does flow, however, I will be sorely disappointed. Task.Run captures ExecutionContext when invoked, and uses it to run the delegate passed to it. That means that the UI SynchronizationContext which was current when Task.Run was invoked would flow into the Task and would be Current while invoking DownloadAsync and awaiting the resulting task. That then means that the await will see the Current SynchronizationContext and Post the remainder of asynchronous method as a continuation to run back on the UI thread. And that means my Compute method will very likely be running on the UI thread, not on the ThreadPool, causing responsiveness problems for my app.

The story now gets a bit messier: ExecutionContext actually has two Capture methods, but only one of them is public. The internal one (internal to mscorlib) is the one used by most asynchronous functionality exposed from mscorlib, and it optionally allows the caller to suppress the capturing of SynchronizationContext as part of ExecutionContext; corresponding to that, there’s also an internal overload of the Run method that supports ignoring a SynchronizationContext that’s stored in the ExecutionContext, in effect pretending one wasn’t captured (this is, again, the overload used by most functionality in mscorlib). What this means is that pretty much any asynchronous operation whose core implementation resides in mscorlib won’t flow SynchronizationContext as part of ExecutionContext, but any asynchronous operation whose core implementation resides anywhere else will flow SynchronizationContext as part of ExecutionContext. I previously mentioned that the “builders” for async methods were the types responsible for flowing ExecutionContext in async methods, and these builders do live in mscorlib, and they do use the internal overloads… as such, SynchronizationContext is not flowed as part of ExecutionContext across awaits (this, again, is separate from how task awaiters support capturing the SynchronizationContext and Post’ing back to it). To help deal with the cases where ExecutionContext does flow SynchronizationContext, the async method infrastructure tries to ignore SynchronizationContexts set as Current due to being flowed.

不过,我不太清楚什么时候这可能会发生。它似乎会在使用公共(public) ExecutionContext.Capture 方法和抑制流动 SynchronizationContext 的内部 Task.Run 重载时发生>ExecutionContext 被使用,但我不知道那会是什么时候。

在我对 .NET 4.5 的测试中,Task.Run 似乎没有使 SynchronizationContextExecutionContext 流动:

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() 会像文章中讨论的那样在 UI 上下文(阻塞 UI 线程)上运行?

最佳答案

When does Task.Run flow SynchronizationContext with ExecutionContext?

从不。

那篇文章的要点是(用于)流动ExecutionContext 的(公共(public)API)将流动SynchronizationContext。但是 Task.Run(以及“几乎所有其核心实现驻留在 mscorlib 中的异步操作”)永远不会这样做。

以“我的期望是有效的”开头的段落是假设性的。他正在描述如果 Task.Run 使用公共(public) API 来流动 ExecutionContext发生什么。这导致问题如果它这样做了。这就是它从不这样做的原因。

关于c# - Task.Run 什么时候流 SynchronizationContext 和 ExecutionContext?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19548389/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com