如何获取调度程序的 TaskScheduler?
我有一个具有多个 Dispatcher(又名 GUI 线程、又名消息泵)的应用程序,以确保 GUI 的缓慢且无响应的部分运行,而不会严重影响应用程序的其余部分。我也经常使用 Task
。
目前,我的代码可以在 TaskScheduler
或 Dispatcher
上有条件地运行 Action
,然后返回 Task
直接或使用 TaskCompletionSource
手动创建一个。然而,这种人格分裂的设计使得处理取消、例外等事情比我想象的要复杂得多。我想在任何地方使用 Task
而在任何地方使用 DispatcherOperation
。为此,我需要在调度程序上安排任务 - 但如何做呢?
如何获取任何给定 Dispatcher
的 TaskScheduler
?
编辑:经过以下讨论,我确定了以下实现:
public static Task<TaskScheduler> GetScheduler(Dispatcher d) {
var schedulerResult = new TaskCompletionSource<TaskScheduler>();
d.BeginInvoke(() =>
schedulerResult.SetResult(
TaskScheduler.FromCurrentSynchronizationContext()));
return schedulerResult.Task;
}
I've got an application with multiple Dispatcher
s (aka GUI threads, aka message pumps) to ensure that a slow, unresponsive portion of the GUI runs without affecting the rest of the application too heavily. I also use Task
a lot.
Currently I've got code that conditionally runs an Action
on a TaskScheduler
or a Dispatcher
and then returns a Task
either directly or by manually creating one using TaskCompletionSource
. However, this split personality design makes dealing with cancellation, exceptions etc. all much more complicated than I'd like. I want to use Task
s everywhere and DispatcherOperation
s nowhere. To do that I need to schedule tasks on dispatchers - but how?
How can I get a TaskScheduler
for any given Dispatcher
?
Edit: After the discussion below, I settled on the following implementation:
public static Task<TaskScheduler> GetScheduler(Dispatcher d) {
var schedulerResult = new TaskCompletionSource<TaskScheduler>();
d.BeginInvoke(() =>
schedulerResult.SetResult(
TaskScheduler.FromCurrentSynchronizationContext()));
return schedulerResult.Task;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
步骤 1:创建扩展方法:
步骤 2:使用扩展方法:
旧语法:
新语法:
Step 1: Create an extension method:
Step 2: Use the extension method:
Old syntax:
New syntax:
不幸的是,没有内置的方法可以做到这一点。没有专门用于在
TaskScheduler
中包装Dispatcher
的内置类 - 我们拥有的最接近的类是包装SynchronizationContext
的类。从SynchronizationContext
构建TaskScheduler
的唯一公共 API 是 Paul Michalik 提到的:TaskScheduler.FromCurrentSynchronizationContext
- 正如您所观察到的,仅当您已经在相关同步上下文中(即在相关调度程序的线程上)时才有效。因此,您有三个选择:
TaskScheduler.FromCurrentSynchronizationContext
正如预期的那样。Dispatcher.BeginInvoke
在调度程序线程上运行一些代码,并在该代码中调用TaskScheduler.FromCurrentSynchronizationContext
。 (换句话说,如果你不能安排 1. 自然发生,那就强迫它发生。)Unfortunately, there's no built-in way to do this. There is no built-in class dedicated to wrapping a
Dispatcher
in aTaskScheduler
- the closest thing we have is the one that wraps aSynchronizationContext
. And the only public API for building aTaskScheduler
from aSynchronizationContext
is the one Paul Michalik mentions:TaskScheduler.FromCurrentSynchronizationContext
- and as you observe, that only works if you're already in the relevent synchronization context (i.e., on the relevant dispatcher's thread).So you have three choices:
TaskScheduler.FromCurrentSynchronizationContext
as intended.Dispatcher.BeginInvoke
to run some code on the dispatcher thread, and in that code, callTaskScheduler.FromCurrentSynchronizationContext
. (In other words, if you can't arrange for 1. to happen naturally, force it to happen.)查看
TaskScheduler.FromCurrentSynchronizationContext
。即使应用程序强加了特定的线程模型,任务框架也提供了一种非常灵活的方法来配置计算绑定操作的执行。编辑:
嗯,很难从您发布的内容中得到更明确的信息。我知道您正在运行某种多视图应用程序,每个视图都有单独的调度程序,对吧?由于所有调度都归结为获取
SynchronizationContext
和Post
- 您可以获取正确的TaskScheduler
(具有正确TaskScheduler
的任务) code>SynchronizationContext) 在您的视图获得同步上下文的某个时刻。一个简单的方法是在配置任务期间获取 TaskScheduler:不确定这是否有帮助,如果您广泛使用任务,您可能已经知道......
Have a look at
TaskScheduler.FromCurrentSynchronizationContext
. The Task framework provides a very flexible way to configure the execution of compute bound operations even if there is a specific threading model imposed by the application.EDIT:
Hm, it is hard to get more explicit from what you have posted. I understand that you´re running sort of multi-view application with separate dispatchers for each view, right? Since all the dispatching boils down to fetching a
SynchronizationContext
andPost
-ing to it you can fetch the rightTaskScheduler
(the one with the correctSynchronizationContext
) at some point where your view(s) got one. A simple way to do that would be to get a TaskScheduler during the configuration of the taks(s):Not sure if this helps, if your are using Tasks extensively you´ll probably already know that...
您可以将整个函数写在一行中:
那些对默认 UI 线程感到满意的人可能会发现以下内容足以满足需要:
You could have written the whole function in one line:
and those who are content with the default UI thread may find the following enough to get by:
尽管没有专门用于将 Dispatcher 包装在 TaskScheduler 中的内置类,但您可以自己编写一个类。完成该工作的示例实现如下所示:
Although there is no built-in class dedicated to wrapping a Dispatcher in a TaskScheduler, you're allowed to write one by yourself. Sample implementation that does the job looks like that:
这就是我总是将异步函数调用转换为同步函数调用的方式(向互联网上的某人致敬):
变化:
That's how I always convert async function call into sync function call (kudos to somebody on the Internet):
Variation: