如何获取Dispatcher的TaskScheduler?

Eam*_*nne 17 .net wpf multithreading task dispatcher

我有一个带有多个应用程序Dispatcher(也就是GUI线程,也就是消息泵)的应用程序,以确保GUI的缓慢,无响应部分运行而不会过多地影响应用程序的其余部分.我也经常使用Task.

目前我已经有条件运行Actiona TaskScheduler或a的代码Dispatcher然后Task直接返回或通过手动创建一个使用TaskCompletionSource.然而,这种分裂的个性设计使得处理取消,异常等等都比我想要的复杂得多.我想在任何地方使用Tasks而且DispatcherOperation无处可去.要做到这一点,我需要在调度员上安排任务 - 但是如何?

如何获得TaskScheduler任何给定的Dispatcher

编辑:在下面的讨论之后,我决定采用以下实现:

public static Task<TaskScheduler> GetScheduler(Dispatcher d) {
    var schedulerResult = new TaskCompletionSource<TaskScheduler>();
    d.BeginInvoke(() => 
        schedulerResult.SetResult(
            TaskScheduler.FromCurrentSynchronizationContext()));
    return schedulerResult.Task;
}
Run Code Online (Sandbox Code Playgroud)

Geo*_*kos 14

第1步:创建扩展方法:

public static Task<TaskScheduler> ToTaskSchedulerAsync (
    this Dispatcher dispatcher,
    DispatcherPriority priority = DispatcherPriority.Normal) {

    var taskCompletionSource = new TaskCompletionSource<TaskScheduler> ();
    var invocation = dispatcher.BeginInvoke (new Action (() =>
        taskCompletionSource.SetResult (
            TaskScheduler.FromCurrentSynchronizationContext ())), priority);

    invocation.Aborted += (s, e) =>
        taskCompletionSource.SetCanceled ();

    return taskCompletionSource.Task;
}
Run Code Online (Sandbox Code Playgroud)

第2步:使用扩展方法:

旧语法:

var taskSchedulerAsync = Dispatcher.CurrentDispatcher.ToTaskSchedulerAsync ();
var taskFactoryAsync = taskSchedulerAsync.ContinueWith<TaskFactory> (_ =>
    new TaskFactory (taskSchedulerAsync.Result), TaskContinuationOptions.OnlyOnRanToCompletion);
// this is the only blocking statement, not needed once we have await
var taskFactory = taskFactoryAsync.Result;
var task = taskFactory.StartNew (() => { ... });
Run Code Online (Sandbox Code Playgroud)

新语法:

var taskScheduler = await Dispatcher.CurrentDispatcher.ToTaskSchedulerAsync ();
var taskFactory = new TaskFactory (taskScheduler);
var task = taskFactory.StartNew (() => { ... });
Run Code Online (Sandbox Code Playgroud)


Ian*_*ths 9

不幸的是,没有内置的方法来做到这一点.有没有内置专门用于包裹一类DispatcherTaskScheduler-我们有最密切的是一个包装了一个SynchronizationContext.为建设唯一的公共API TaskSchedulerSynchronizationContext是一个保罗·米哈利克提到:TaskScheduler.FromCurrentSynchronizationContext-和你观察,仅如果在培训相关的同步环境是已经(即,有关调度的线程)的作品.

所以你有三个选择:

  1. 安排您的代码,以便需要相关调度程序的调度程序的类在某些时候有机会在这些调度程序的线程上运行,以便您可以TaskScheduler.FromCurrentSynchronizationContext按预期使用.
  2. 用于Dispatcher.BeginInvoke在调度程序线程上运行一些代码,并在该代码中调用TaskScheduler.FromCurrentSynchronizationContext.(换句话说,如果你不能自然地安排1.强迫它发生.)
  3. 编写自己的任务调度程序.