您是否像这样运行任务(而不是 Task
):
public async void button1_click(...)
{
await Task.Run(...);
}
或在您调用
InvokeRequired
的旧方法上使用检查是否需要在另一个同步上下文上调用当前操作,然后调用 Control.Invoke
(例如,在 WinForms 的情况下),如果有同步上下文,则使用捕获的同步上下文执行操作。然而,这意味着哪两件事?
如果您使用任何方法(无论是旧方法还是新方法)请求在线程池线程上运行任务,这是否意味着:
或
System.Threading.ExecutionContext.SynchronizationContext
) 的切换,因此,同步上下文只是一个协作规则线程同意遵守?工作还是会由线程池线程来完成?当然,通过合作纪律*,我并不是说即使恶意线程决定不在需要的地方切换同步上下文,一切都会正常进行。我的意思是,如果同步上下文引用更改为正确的,最初不拥有同步上下文的线程仍然可以运行。
来自阅读
AsyncMethodBuilder<TResult>.Start
的源代码, System.Threading.Tasks.Task.ExecuteWithThreadLocal
和 System.Threading.ExecutionContext.RunInternal
方法,答案似乎很可能是#2,但我不确定。更新
这也是为什么我认为#2更有可能,但我很想得到纠正。
如果您只是拿一个 Windows 窗体应用程序并在其上粘贴一个按钮并在 click 事件中运行图片中显示的代码,您可能会看到类似于我的调用堆栈,如图所示。
我在调用堆栈中跟踪了每个方法的源代码。我观察到上下文切换发生在
System.Threading.ExecutionContext.RunInternal
方法。发生这种情况是因为 System.Threading.Tasks.ExecuteWithThreadLocal
方法传递值 true
用于调用 System.Threading.ExecutionContext.Run
的最后一个参数方法。请看 line 2823 .但是,此后,调用继续进行,没有任何消息发布到 UI 线程的消息队列,并且当它最终到达
System.Threading.Tasks.Task<TResult>.InnerInvoke
时。方法,该方法调用委托(delegate)。如果答案是#1,请告诉我消息发布的位置,我会高兴得跳起来,今天会学到一些关于同步上下文的有趣的东西。
是否发生在
ExecutionContext.SetExecutionContext
方法?如果答案是#2,如果你能证实这一点,那么,我也会唱一首歌来庆祝我的发现。
Side Note
I made this program to test something different, though. I wanted to see where the synchronization context is switched, if it is required, both:
- Before the
await
statement is reached; and- After the
await
statement, i.e on the continuation callback.And my findings have satisfactorily revealed to me the answers to both the questions.
For anyone curious, the switch is made in the
AsyncMethodBuilder
'sStart
method for any code that is before theawait
expression.For code that is after, there is more than one path. One of the paths is depicted in this call stack that is shown in the picture above.
最佳答案
我有一个 async
intro blog post这解释了 await
与 SynchronizationContext.Current
合作.具体来说,await
使用捕获的上下文来恢复 async
方法。
所以,这是不正确的:
the operation is performed using the captured synchronization context, if there is one.
如果通过“操作”,您的意思是
...
在您的代码中:public async void button1_click(...)
{
await Task.Run(...);
}
会发生什么
Task.Run
将安排...
到线程池线程(Task.Run
总是使用线程池)。 await
然后捕获当前 SynchronizationContext
(在本例中为 UI 上下文)并返回。当...
完成,然后Task.Run
返回的任务将完成,button1_click
将在该上下文(UI 线程)上恢复。然后它到达方法的末尾并返回。内
...
, SynchronizationContext.Current
将是 null
.是await
设置的任务延续使用其捕获的 SynchronizationContext
在 UI 线程上恢复。
关于.net - 同步上下文的切换是否意味着工作将在拥有同步上下文的线程上运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37666430/