我有一堆线程被阻塞等待消息。每条消息都有一个指向特定线程的ID。我有以下实现:
1)所有线程都使用Monitor.Wait
在同一个锁对象上等待。当收到消息时,我调用Monitor.PulseAll
并且每个线程使用消息ID检查自己的ID。如果匹配,则线程继续。否则它会再次在同一个对象上等待。使用这种方法,每个消息到达都会导致N-1个线程被唤醒并且ID不匹配并重新进入休眠状态。
2)每个线程创建一个ManualResetEvent
并将其添加到字典中。字典将消息id映射到其事件。当消息到达时,它会调用map[message.Id].Set()
来唤醒特定的线程。
3)最后一个实现与#2非常相似,只是它使用了一个锁对象而不是ManualResetEvent
。假设ManualResetEvent
是一个昂贵的对象。与ManualResetEvent
相比,这种方法更复杂。
这里最好的方法是什么?还有更好的吗?
答案 0 :(得分:3)
问题描述相当模糊,因此很难确定您的最佳方法是什么。那说......
我根本不会使用#1或#2。 #1需要唤醒每个线程,因此一个线程可以运行,这显然效率低下,而#2使用非托管的基于Windows的同步对象,效率不高使用内置的.NET机制。
鉴于问题描述,您的#3选项面对它并非不合理。但是,恕我直言,你不应该自己重新实现这一点。即就我所知,你(由于某种原因)有需要提供给特定线程的消息,即给定的消息必须只由一个特定的线程处理。
在这种情况下,我认为您应该为每个线程创建一个单独的消息队列,并将消息添加到适当的队列中。有很多方法可以实现队列,但对于这个特定的例子来说,最明显的是使用BlockingCollection<T>
。默认情况下,它使用队列作为基础集合数据结构。另一个重要的功能是GetConsumingEnumerable()
方法,它允许您在依赖线程中编写foreach
循环,以便在排队时检索消息。当没有消息可用时,循环将阻塞,等待通过其他线程提供消息。
您可以使用字典将消息ID映射到每个线程的相应队列。
请注意,这不是真的恕我直言的性能问题。它更多的是针对给定问题使用适当的数据结构。即您似乎有一个消息队列,您希望根据其ID将每个消息分派到不同的线程。相反,我认为您应该实现多个消息队列,每个线程一个,然后使用现有的.NET功能来实现您的逻辑,这样您就不必重新发明轮子。
另请注意,如果您仍然必须为邮件维护单个输入队列(例如,因为该界面呈现给您程序中的某个其他组件),您仍然可以并且仍然应该执行上述操作。您只需要一些适配器代码,这些代码可以从主要的单个消息队列中取消消息,并路由到相应的特定于线程的队列。
答案 1 :(得分:0)
Thread.Start()
。Thread.IsAlive
属性。Thread.ThreadState()
。您可以使用上述三种道具和方法对线程进行所需的控制,并以非常精细的粒度进行管理。
初始化线程时,请将它们全部放在Dictionary<ID, Thread>()
中。现在,无论何时收到消息,只需获取具有所需ID的线程并将其唤醒即可。