我仍在学习整个任务概念和TPL。根据我目前的理解,await
使用SynchronizationContext函数(如果存在)在某处“调度”任务。另一方面,Task
类中的函数不使用上下文,对吧?
因此,例如Task.Run(...)
将始终在线程池的工作线程上调度操作,并完全忽略SynchronizationContext.Current
。 await Foobar()
将使用上下文在await
?
如果这是真的,我的问题是:我如何获得Task
,实际上运行某个操作但是使用SynchronizationContext.Current.Send/Post
调度?
任何人都可以向SynchronizationContext
推荐一个很好的介绍,特别是在框架的其余部分使用它们的时间和方式?关于班级,MSDN似乎非常安静。 Google热门点击(here和here)似乎仅适用于Windows Forms调度。 Stephen Cleary写了an article,这很好地了解了已经存在的情境以及它们是如何工作的,但我不了解它们在何时何地实际使用。
答案 0 :(得分:39)
如何获取实际运行操作但使用调度的任务 SynchronizationContext.Current.Send /后?
使用特殊任务调度程序:
Task.Factory.StartNew(
() => {}, // this will use current synchronization context
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
任何人都可以向SynchronizationContext推荐一个很好的介绍
请看Stephen Cleary的文章It's All About the SynchronizationContext。
答案 1 :(得分:26)
在您了解这一点时,重要的是要指出TPL 使用的Task
与async /使用的Task
完全不同等待,即使它们属于同一类型。例如,TPL通常使用父/子任务,但async
/ await
不会。
TPL使用任务调度程序来执行其任务。正如Dennis指出的那样,TaskScheduler.FromCurrentSynchronizationContext
将为您提供一个任务调度程序,它使用当前Post
上的SynchronizationContext
来执行其任务。
async
/ await
通常不使用任务计划程序。我在我的博客上有一个介绍async
/await
post,其中包含了上下文信息,我在MSDN article中也简要提到了它(虽然很容易忽略)。基本上,当async
方法在await
处暂停时,默认情况下它会捕获当前SynchronizationContext
(除非它是null
,在这种情况下它会捕获当前TaskScheduler
{1}})。当async
方法恢复时,它将继续在该上下文中执行。
Dennis指出了将任务安排到当前SynchronizationContext
的TPL方式,但在async
/ await
世界中,这种方法并不是必需的。相反,您可以通过Task.Run
async Task MyMethodAsync()
{
// Whee, on a SynchronizationContext here!
await Task.Run(() => { }); // Ooo, on the thread pool!
// Back on the SynchronizationContext ...
// ... automagically!
}
我正好写了我的SynchronizationContext
文章,因为MSDN文档非常缺乏。我有little more information on my blog,但所有重要的位都在MSDN文章中。许多类型直接使用AsyncOperation
而不是SynchronizationContext
;最好的文档是buried under the EAP docs (section "Threading and Context")。但我还应该指出,由于async
/ await
,EAP实际上已经过时了,所以我不会使用AsyncOperation
(或SynchronizationContext
)来编写代码 - 除非我是实际上写我自己的 SynchronizationContext
。