处理队列成员

时间:2011-10-18 07:38:32

标签: c# multithreading .net-4.0 queue parallel-processing

我有一个填充队列的线程。我有另一个处理此队列的线程。我的问题是第一个线程非常快地填充队列,因此其他线程无法更快地处理此队列,并且我的程序保持过度使用ram。这个问题的最佳解决方案是什么?

抱歉,我忘了添加一些东西。我不能限制我的队列或生产者线程。我的生产者线程不能等待,因为它捕获网络数据包,我不应该错过任何数据包。我必须比生产者线程更快地处理这些数据包。

5 个答案:

答案 0 :(得分:0)

好吧,假设队列中项目的处理顺序不重要,您可以运行处理队列的两个(或更多)线程。

除非它们之间存在某种争用,否则应该能够加快处理速度。这被称为多消费者模型。

另一种可能性是让您的生产者线程监视队列的大小,并拒绝添加条目,直到它低于某个阈值。标准C#队列不提供阻止扩容的方法(即使使用1.0增长因子也不会抑制增长)。

答案 1 :(得分:0)

你可以定义一个最大队列大小(假设是2000),当命中时会导致队列只接受更多的项目(比如1000)。

我建议使用EventWaitHandle或ManualResetEvent以免忙碌等待。 http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent.aspx

答案 2 :(得分:0)

除非您已经这样做,否则请使用BlockingCollection<T>作为队列,并将一些合理的限制传递给构造函数的boundedCapacity参数(然后将其反映在BoundedCapacity属性中) - 您的生产者将阻塞Add,如果这会使队列过大,并在消费者从队列中删除一些元素后继续。

根据MSDN documentation for BlockingCollection<T>.Add

如果在初始化此BlockingCollection<T>实例时指定了有界容量,则对Add的调用可能会阻塞,直到空间可用于存储提供的项目。

答案 3 :(得分:0)

另一种方法是在启动时使用new()X线程间通信实例,将它们放在队列中,永远不再创建。线程A从该池队列中弹出对象,用数据填充它们并将它们排队到线程B.线程B获取对象,处理它们然后将它们返回到池队列。

这提供了流量控制 - 如果线程A试图发布得太快,则池将干涸,A将必须等待池队列,直到B返回对象。它有可能提高性能,因为在初始池填充后没有mallocs和释放 - 队列push / pop上的锁定时间将小于内存管理器调用的锁定时间。不需要复杂的有界队列 - 任何旧的生产者 - 消费者队列类都可以。该池可用于整个应用程序中的线程间通信,包含许多线程/ threadPools,因此可以对它们进行流量控制。关闭问题可以减轻 - 如果池队列是由主线程在启动之前在任何表单之前创建的,并且从未释放过,那么通常可以避免应用程序关闭时显式的后台线程关闭 - 这会让人忘记。通过监视池级别('检测到',而不是'固定':)可以轻松检测到对象泄漏和/或双重释放。

不可避免的缺点 - 即使应用程序完全空闲,所有的线程间通信实例内存也会永久分配。从池中弹出的对象将充满前一次使用它的“垃圾”。如果'slowest'线程在释放一个对象之前得到一个对象,则应用程序可能会因为池空并且所有对象排队到最慢的线程而死锁。当一个更简单的“新/队列/处置”机制只分配更多实例时,一个非常大的加载爆发可能导致应用程序“提前”限制自己,因此随着工作的爆发更好地缓存。

RGDS, 马丁

答案 4 :(得分:0)

最简单的解决方案是生产者线程检查队列是否已达到待处理项目的某个限制,如果是,则在推送更多工作之前进入休眠状态。 其他解决方案取决于您尝试解决的实际问题,处理更多IO绑定或CPU绑定等,甚至可以让您设计甚至不需要队列的解决方案。例如:生产者线程可以生成,可以说10个项目,并调用另一个消费者“方法”,它们并行处理它们等等。