Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
WPF Dispatcher是多线程问题的解决方案吗?_Wpf_Multithreading_Dispatcher - Fatal编程技术网

WPF Dispatcher是多线程问题的解决方案吗?

WPF Dispatcher是多线程问题的解决方案吗?,wpf,multithreading,dispatcher,Wpf,Multithreading,Dispatcher,对于在代码中使用lock,我有一种非常不好的感觉,但是现在WindowBase的Dispatcher已经存在,我想在任何地方都使用它 例如,我使用了一个多线程单线程WCF服务,它在PRISM的EventAggregator上发布事件,负载是不可变的(它只是数据),每个具有dispatcher的线程都可以优雅地检索事件,而不会在自己的dispatcher中出现死锁。(不仅是UI线程,还有数据库调用线程、服务调用线程、日志线程或其他调用缓慢的线程,因为我不想冻结UI) 但我的问题是,这个调度器与WP

对于在代码中使用lock,我有一种非常不好的感觉,但是现在WindowBase的Dispatcher已经存在,我想在任何地方都使用它

例如,我使用了一个多线程单线程WCF服务,它在PRISM的EventAggregator上发布事件,负载是不可变的(它只是数据),每个具有dispatcher的线程都可以优雅地检索事件,而不会在自己的dispatcher中出现死锁。(不仅是UI线程,还有数据库调用线程、服务调用线程、日志线程或其他调用缓慢的线程,因为我不想冻结UI)

但我的问题是,这个调度器与WPF结合在一起,所以当我到处使用它时,我感到有点内疚,我觉得这个调度器不是为我的用例而创建的

是否存在未与WPF耦合的另一个Dispatcher实现?还是可以滥用它

谢谢

更新

Paul Stovell给我的解决方案是为Wpf Dispatcher创建一个接口IDispatcher和一个适配器,因此这将更容易测试! 这个解决方案对我很好,因为我重构了测试,现在可以在测试中使用SynchronousDispatcherAdapter(多亏了它,我不必在测试中使用WPF的Dispatcher)

使用Dispatcher而不是BackgroundWorker是有意义的,因为我使用的是多发布者/订阅者模式(使用PRISM),而且由于Dispatcher,每个事件处理程序都会在订阅事件的线程上调用。这意味着多线程问题唯一可能发生的点是我事件的有效负载(我使他不可变)

我的不同线程之间不直接通信,它们只能发布和订阅事件。 因此,数据库调用、日志调用、服务调用和UI调用在不同的线程上运行,彼此不了解(它们只知道订阅和发布的事件)

当我从UI调用存储库时,后台工作人员将是有意义的


但我希望找到一种不使用BackgroundWorker的设计,因为我更喜欢使用订阅者/发布者模式(我认为它使我的代码更可读)

是和否。。这是一个渲染的东西,而不是线程本身

调度员根据优先级选择工作项,并运行每个工作项直到完成。每个UI线程必须至少有一个调度程序,每个调度程序只能在一个线程中执行工作项。根据微软公司的消息

您仍然必须自己处理自己启动的任何线程

检查以下信息:使用基于事件的异步模式进行多线程编程

就我个人而言,我使用的线程的需要


.

使用Dispatcher(或BackgroundWorker)的主要问题是很难进行测试,除非您的测试工具实际上有一个UI线程

解决方案1 使用。它提供了在UI线程上调用的相同功能,并在Windows或WPF中工作。测试它

解决方案2 将调度程序看作是另一个服务。在使用PRISM时,您熟悉服务和IOC。以下是如何使用此类服务:

// Not a UI component
public class MyDomainService : IMyDomainService
{
   private readonly IDispatcher _dispatcher;

   public MyDomainService(IDispatcher dispatcher) 
   {
      _dispatcher = dispatcher;
   }

   private void GotResultFromBackgroundThread()
   {
       _dispatcher.Dispatch(() => DoStuffOnForegroundThread());
   }
}
这允许您在不同的实现中替换平台/测试


下面是a和a的示例。您可以像任何其他服务一样在IOC容器中注册它们,并且它们对UI和其他服务都可用

我要彻底解决这个问题,但这听起来是个坏主意。您的意思是,您的发布者需要一个队列来为其订阅者转储项目。调度器的核心只是一个美化的队列,周围有很多开销。开销专门用于保护对UI资源的访问,而您不使用这些资源。这表明使用它是错误的

建议SynchronizationContext的人走上了一条很好的道路。这可以实现您想要的(安全地将数据编组到另一个线程),而无需将您绑定到UI概念。您可以编写一个扩展方法,将事件封送到事件的每个订阅者请求的SynchronizationContext(可以通过将订阅委托的目标强制转换为ISynchronizeInvoke来实现)。强制转换的结果将允许您知道是否需要对其进行marhalled,并可以自动为您执行此操作


更好的做法是只使用具有适当锁定语义的队列。锁的开销不太可能是一个问题,如果是的话,那么使用Dispatcher将比使用简单的锁更具破坏性。在这种情况下,越简单越好。它们的关键是只保留锁以在队列中添加/删除项目。订阅rs应该执行锁之外的任何工作。

PRISM使用IDispatcherFacade,我扩展了他们的类CompositePresentationEvent,并添加了一个重载来订阅:SubscriptionToken Subscribe(Action、IDispatcherFacade、bool、Predicate),因此它很容易测试(Wpf适配器可以直接编码)你不必有UI线程,因为你可以使用dispatcher.CurrentAh在任何线程上创建一个dispatcher。好的,对不起,我忘记了当我使用注入接口时,我不再与WPF耦合,谢谢;)BackgroundWorker使用dispatcher,因为在UI线程上调用RunWorkerCompleted,所以我认为这和我的解决方案没什么不同。使用异步事件模式,您必须小心地使用锁保护共享资源(我希望避免这种情况)。对于Dispatcher对象,它们有自己的线程。Slashene,Dispatcher使用相同的UI线程。它像后台工作人员一样将自己推到windows消息泵上,因此它需要与后台工作人员相同的锁定量。dispatcher和BackgroundWorker之间的区别在于,您可以决定代码将执行哪个线程。