Threading.Tasks.TaskScheduler - 请帮我把脑筋包起来

时间:2011-01-28 20:55:20

标签: .net task

我正在开发一个应用程序,后台进程会运行很长一段时间,我想向UI报告进度。我想在.Net 4.0中使用任务,以便我对它们有所了解。我找到了Stephen Cleary的精彩文章,其中包含了一个类,即ProgressReporter(文章链接在底部)。

我可以直接上课并按原样使用它,但后来我不拥有这些知识。我根本无法理解的部分是关于TaskScheduler对象。我已经阅读了文档,但它假设我已经知道调度程序是什么而我实际上并不知道。

从Stephen的文章看来,如果我使用“FromCurrentSynchronizationContext”创建一个TaskScheduler,从即将启动后台任务的事件开始,那么我可以在异步进程中使用该TaskScheduler实例创建一个新任务然后可以访问UI控件,并且实际上将在UI线程上运行。

至少从干净优雅的代码看起来就是这样。

有人可以帮我理解TaskScheduler(或只是一个调度程序)是什么,以便“FromCurrentSynchronizationContext”有意义吗?

非常感谢!

引用文章的链接: http://nitoprograms.blogspot.com/2010/06/reporting-progress-from-tasks.html

1 个答案:

答案 0 :(得分:4)

首先,要了解Task本身与ThreadPool无关。将Task视为一个工作单元是有帮助的,仅此而已。它实际上只是一个花哨的代表。

TaskScheduler可以运行Task。默认TaskSchedulerTask上运行ThreadPool,但这不是唯一的TaskScheduler。您可以致电TaskScheduler.FromCurrentSynchronizationContext以获取在UI线程上运行TaskScheduler的{​​{1}}。

ParallelExtensionsExtras库包含几个有趣的Task。有关详细信息,请参阅this series中的第5,6和7个帖子。

所以,回到我的TaskScheduler课程,我正在做的是:

  • 在UI线程上创建ProgressReporter,它捕获将在UI线程上运行ProgressReporter的{​​{1}}。
  • 然后,您运行后台TaskScheduler(其中“背景”表示它在Task上的默认Task上运行)。
  • 当后台TaskScheduler想要报告进度时,会创建 ThreadPool并将其发送到用户界面Task

我应该指出Async CTP使用的方法略有不同。他们建议需要报告进度的任务采用Task参数(这是一个好主意)。然后他们提供了一个实现(TaskScheduler),它在捕获的IProgress<T>上引发了一个事件。使用EventProgress<T>与我的SynchronizationContext类似,但有两个重要区别:

  • EventProgress<T>方法让使用者定义对进度更新的响应。我的ProgressReporter生产者(后台操作)定义了对进度更新的响应。
  • IProgress<T>将立即返回,允许后台操作继续。默认情况下,ProgressReporter将等待UI更新。

IProgress<T>是更好的设计,因为第一点(尽管我认为ProgressReporter在使进度报告同步时更正确)。 IProgress<T>当时很好,并且可以敲出一些快速代码,但是如果你正在设计一个可重复使用的背景组件,请使用与ProgressReporter类似的东西。

如果您不熟悉Async CTP,我强烈建议您查看它。它还没有为生产使用做好准备,但你至少应该阅读“基于任务的异步模式”的论文。它显示了事情的进展,并且是设计使用ProgressReporter s的API的经过深思熟虑的方法。

P.S。我上面做了几个简化:

  • IProgress<T>只是一个工作单位,甚至不是一个“花哨的代表”。实际上,工作单元实际上可以由另一个程序完成,在这种情况下,根本没有委托附加到Task对象。您可以使用Task类创建这些抽象的“工作单元”。
  • 我没有进入Task或者为什么用它来安排UI的工作。从本质上讲,它是一个“委托调度程序” - 如果您将委托视为“工作单元”,可以使用TaskCompletionSource来运行委托。更多信息将在下周的MSDN 2月刊中发布。