Threading.Tasks.TaskScheduler - 请帮我解决这个问题
我正在开发一个应用程序,该应用程序将运行相当长一段时间的后台进程,并且我想向 UI 报告进度。我想使用 .Net 4.0 中的任务,以便对它们有一个有效的理解。我发现 Stephen Cleary 写的一篇精彩文章展示了这一点,并包含一个类 ProgressReporter(文章链接在底部)。
我可以直接上课并按原样使用它,但我并不拥有这些知识。我根本无法理解的部分是关于 TaskScheduler 对象。我已阅读文档,但它假设我已经知道调度程序是什么,但实际上我不知道。
从 Stephen 的文章来看,如果我使用“FromCurrentSynchronizationContext”从即将启动后台任务的事件中创建一个 TaskScheduler,那么我可以在异步进程中使用该 TaskScheduler 实例来创建一个新任务,然后该任务将具有访问 UI 控件,并且实际上将在 UI 线程上运行。
至少从干净、优雅的代码来看是这样的。
有人可以帮助我理解 TaskScheduler (或只是一个 Scheduler)是什么,以便“FromCurrentSynchronizationContext”有意义吗?
非常感谢!
参考文章链接: http://nitoprograms.blogspot.com/2010/06/reporting -progress-from-tasks.html
I am working on an application that will have a background process running for quite a while and I want to report progress to the UI. I want to use Tasks in .Net 4.0 so that I gain a working understanding of them. I found a wonderful article by Stephen Cleary that shows this and includes a class, ProgressReporter (article link at the bottom).
I could just take the class and use it as-is, but then I don't own the knowledge. The part that I simply cannot understand is regarding the TaskScheduler object. I have read the documentation, but it makes the assumption that I already know what a Scheduler is and I don't, actually.
From Stephen's article it appears that if I create a TaskScheduler, using "FromCurrentSynchronizationContext", from the event that's about to kick off the background task, then I can use that TaskScheduler instance from within the async process to create a new task that will then have access to UI controls and will, in fact, be running on the UI thread.
At least that's what it looks like from the clean, elegant code.
Can someone help me understand what a TaskScheduler (or just a Scheduler) is so that the "FromCurrentSynchronizationContext" makes sense?
Thanks so much!
Link to article referenced:
http://nitoprograms.blogspot.com/2010/06/reporting-progress-from-tasks.html
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
首先,请了解
Task
本身与ThreadPool
没有关系。将Task
视为一个工作单元会有所帮助,仅此而已。它实际上只是一个花哨的代表。TaskScheduler
是可以运行Task
的东西。默认的TaskScheduler
在ThreadPool
上运行Task
,但这并不是唯一的TaskScheduler
。您可以调用TaskScheduler.FromCurrentSynchronizationContext
来获取在 UI 线程上运行Task
的TaskScheduler
。ParallelExtensionsExtras 库包含几个有趣的
TaskScheduler
。有关详细信息,请参阅 此中的帖子 5、6 和 7系列。因此,回到我的
ProgressReporter
类,我正在做的是:ProgressReporter
在 UI 线程上创建,它捕获TaskScheduler< /code> 将在 UI 线程上运行
Task
。Task
(其中“后台”意味着它在ThreadPool
上的默认TaskScheduler
上运行)。Task
想要报告进度时,它会创建一个新
Task
并将其发送到 UITaskScheduler
。我应该指出,异步 CTP 使用略有不同的方法。他们建议需要报告进度的任务采用
IProgress
参数(这是一个好主意)。然后,它们提供一个实现 (EventProgress
),该实现在捕获的SynchronizationContext
上引发事件。使用EventProgress
与我的ProgressReporter
类似,但有两个重要区别:IProgress
方法具有消费者 em> 定义对进度更新的响应。我的ProgressReporter 让生产者(后台操作)定义对进度更新的响应。IProgress
将立即返回,允许后台操作继续。ProgressReporter
默认情况下会等待 UI 更新。由于第一点,
IProgress
是更好的设计(尽管我认为ProgressReporter
在使进度报告同步方面更正确)。ProgressReporter
当时还不错,可以快速编写一些代码,但如果您正在设计可重用的后台组件,请使用类似于IProgress
的东西。如果您不熟悉 Async CTP,我强烈建议您查看一下。它尚未准备好用于生产,但您至少应该阅读“基于任务的异步模式”论文。它显示了事情的进展情况,并且是一种经过深思熟虑的设计使用
Task
的 API 的方法。PS 我在上面做了一些简化:
Task
对象。您可以使用TaskCompletionSource
类创建这些抽象的“工作单元”。SynchronizationContext
来运行委托。更多信息将在下周的 MSDN 二月号中发布。First, understand that a
Task
by itself has no relation to theThreadPool
. It helps to think of aTask
as a unit of work, nothing more. It's actually just a fancy delegate.A
TaskScheduler
is something that can run aTask
. The defaultTaskScheduler
runsTask
s on theThreadPool
, but that's not the onlyTaskScheduler
around. You can callTaskScheduler.FromCurrentSynchronizationContext
to get aTaskScheduler
that runsTask
s on a UI thread.The ParallelExtensionsExtras library includes several interesting
TaskScheduler
s. For details, see posts 5, 6, and 7 in this series.So, to come back to my
ProgressReporter
class, what I'm doing is this:ProgressReporter
is created on the UI thread, and it captures theTaskScheduler
that will runTask
s on the UI thread.Task
(where "background" means that it's running on the defaultTaskScheduler
- on theThreadPool
).Task
wants to report progress, it creates a newTask
and sends it to the UITaskScheduler
.I should point out that the Async CTP uses a slightly different approach. They recommend that tasks needing to report progress take an
IProgress<T>
argument (which is a great idea). Then they provide an implementation (EventProgress<T>
), which raises an event on a capturedSynchronizationContext
. UsingEventProgress<T>
is similar to myProgressReporter
with two important differences:IProgress<T>
approach has the consumer define the response to the progress update. MyProgressReporter
has the producer (the background operation) define the response to the progress update.IProgress<T>
will return immediately, allowing the background operation to continue.ProgressReporter
by default will wait until the UI has been updated.The
IProgress<T>
is the better design, because of the first point (though I'm of the opinion thatProgressReporter
is more correct in making the progress reporting synchronous).ProgressReporter
was fine for the time, and it's OK for banging out some quick code, but if you're designing a reusable background component, use something similar toIProgress<T>
.If you aren't familiar with the Async CTP, I highly recommend checking it out. It's not ready for production use yet, but you should at least read the "Task-based Asynchronous Pattern" paper. It shows where things are going, and is a well-thought-out approach to designing APIs that use
Task
s.P.S. There are a couple of simplifications I made above:
Task
s are really just a unit of work, not even a "fancy delegate". In fact, the unit of work may actually be done by another program, in which case there is no delegate attached to theTask
object at all. You can create these abstract "units of work" by using theTaskCompletionSource
class.SynchronizationContext
is or why it's used to schedule work to the UI. In essence, it's a "delegate scheduler" - if you consider a delegate as a "unit of work", aSynchronizationContext
can be used to run delegates. More information will be in the MSDN February issue next week.