非UI线程上的WPF Dispatcher

时间:2014-02-22 02:21:24

标签: c# .net wpf multithreading begininvoke

根据MSDN,Dispatcher 提供管理线程工作项队列的服务。

一个简单的问题。我想仅使用Dispatcher:作为工作项的队列(通过Dispatcher.BeginInvoke发布),我的后台线程将以连续方式提供。

我不想让这个线程成为一个STA线程,我不需要在它上面输入Windows消息。这个帖子上没有用户界面。

使用Dispatcher是否合法?

2 个答案:

答案 0 :(得分:4)

  

这是使用Dispatcher的合法方式吗?

可以 use a secondary thread with a Dispatcher,但这种情况并不常见。通常这样做是为了使UI的不同部分在不同的UI线程上运行。调度程序线程将处理Windows消息,并且必须是STA。另外,从技术上讲,处理不是严格的FIFO,因为调度的项目优先排队。

尽管如此,即使它没有设计为在没有用户界面的情况下使用,你也可以以这种方式使用它。

备选方案:

1)AsyncContextThread是一个带有AsyncEx NuGet库工作队列的简单线程:

private readonly AsyncContextThread _thread = new AsyncContextThread();
...
_thread.Factory.StartNew(() => { ... });

AsyncContextThread类型为其运行的代码提供SynchronizationContext,因此默认情况下async个连续将在同一个线程上恢复。

2)如果只是串行处理请求并且实际上并不重要他们运行的线程,那么您可以使用任务scheduler指示线程池一次运行一个请求,如下所示:

private readonly TaskFactory _factory = new TaskFactory(
    new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler);
_factory.StartNew(() => { ... });

答案 1 :(得分:3)

简答:

如果您需要实际使用Dispatcher运行时组件,例如System.Windows.Media.Imaging,那么我有一个答案。如果您没有使用Dispatcher运行时组件,那么甚至不要考虑使用Dispatcher运行时。请改用任务并行库(TPL)。

答案很长:

我在大批量制作服务中构建并使用this DispatcherTaskScheduler implementation。您可以使用尽可能多的线程来配置它以拥有一个池(默认为核心数),它将负责启动这些线程,使用Dispatcher运行时初始化它们然后排队并向他们派遣工作。适用于TPL,TPL DataFlow,SynchronizationContext样式编程(例如异步/等待)等。

基本用法如下所示:

Task.Factory.StartNew(() =>
{
   // Do anything you want with Dispatcher components here
},
CancellationToken.None,
TaskCreationOptions.None,
DispatcherTaskFactory.Default);

如果您配置自己的实例(例如,您需要更多线程),那么只需将DispatcherTaskFactory.Default替换为您的实例。我的建议是不要配置比核心更多的线程(只使用Default实例),并确保你只尝试在这些线程上进行Dispatcher运行时工作。

正如我所提到的,我在与图像处理相关的软件系统的几个部分中使用了这个实现,这些部分是我们业务的核心,并且承受了大量的负载,并且它已经证明对我们来说绝对是防弹。

最后,免责声明:Microsoft并不真正支持像这样使用的Dispatcher运行时。