我仍在学习整个任务概念和 TPL。根据我目前的理解,
await
使用 SynchronizationContext 函数(如果存在)将任务分派到“某处”。另一方面,Task
类中的函数不使用上下文,对吧?
因此,例如
Task.Run(...)
将始终在线程池的工作线程上分派操作,并完全忽略 SynchronizationContext.Current
。 await Foobar()
将使用上下文在 await
? 之后执行生成的任务
如果这是真的,我的问题是:如何获得一个
Task
,它实际上运行一个操作,但使用 SynchronizationContext.Current.Send/Post
调度?
任何人都可以推荐一个关于
SynchronizationContext
的很好的介绍,特别是框架的其余部分何时以及如何使用它们? MSDN 似乎对这门课很安静。 Google 的热门搜索(here 和 here)似乎仅针对 Windows 窗体调度而定制。 Stephen Cleary 写了一篇文章,很高兴了解已经存在的上下文以及它们如何工作,但我缺乏对它们实际使用的地点和时间的了解。
如何获得一个任务,该任务实际上运行一个操作,但使用 SynchronizationContext.Current.Send/Post?
使用特殊的任务调度程序:
Task.Factory.StartNew(
() => {}, // this will use current synchronization context
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
任何人都可以推荐 SynchronizationContext 的一个很好的介绍吗
查看 Stephen Cleary 的文章 It's All About the SynchronizationContext。
在学习这一点时,需要指出的是,TPL
使用的
Task
与 async/await使用的
Task
有很大不同,尽管它们是同一类型。例如,TPL 通常使用父/子任务,但 async
/await
则不使用。
TPL 使用任务调度程序来执行其任务。正如 Dennis 指出的,
TaskScheduler.FromCurrentSynchronizationContext
将为您提供一个任务调度程序,它在当前 Post
上使用 SynchronizationContext
来执行其任务。
async
/await
通常不使用任务调度程序。我的博客上有一篇介绍性的 async
/await
帖子,其中包含上下文信息,我还在我的 MSDN 文章 中简要提到过它(不过,它很容易被忽视)。本质上,当 async
方法在 await
暂停时,默认情况下它将捕获当前 SynchronizationContext
(除非它是 null
,在这种情况下它将捕获当前 TaskScheduler
)。当 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文档太缺乏了。我的博客上有更多信息,但所有重要信息都在 MSDN 文章中。许多类型直接使用 AsyncOperation
而不是 SynchronizationContext
;最好的文档是埋在 EAP 文档中(“线程和上下文”部分)。但我还应该指出,由于 async
/await
,EAP 实际上已过时,所以我不会使用 AsyncOperation
(或 SynchronizationContext
)编写代码 - 除非我实际上是 编写自己的 SynchronizationContext
.