通过googling搜索,似乎并不是真的推荐使用表来实现生产者/消费者模式。最棘手的部分是拥有多个消费者。
我不知道为什么。如果不是让多个进程/线程试图声明记录,而是我们应该确保它们不会声明相同的记录等等,那么拥有一个消费者来获取记录,将它们传递给进行处理并最终更新相关记录的forked进程,这难道不是相同的吗?
这种设计似乎有相同的结果,因为有多个消费者,但没有缺点。
我是不是误解了什么,比如事务智能、锁定等?
发布于 2014-04-04 00:35:38
我发现使用多个使用者要容易得多,因为它们都服务于一个线程安全的队列。该程序的一般结构如下:
var queue = some thread-safe queue
// multiple consumer threads that all do this
consumer:
while (queue.Take(item))
{
process(item);
}请注意,队列的Take方法执行非繁忙等待(通常使用某种monitor。
生产者向队列中添加内容:
producer:
while (items available from input)
{
queue.Add(item);
}对我来说,这是一个简单得多的设计,因为我只需要设置一次。队列数据结构被设计为支持多个生产者和多个消费者。它为你处理所有的同步。
如果你以另一种方式来做这件事,只有一个消费者线程服务于队列,并在必要时触发工作线程,它就会变得混乱。使用者线程必须跟踪当前有多少工作线程正在运行,并在工作线程完成时接收通知。工作线程不仅要关注项目的处理,还要在工作完成时进行通知。结果是,您的代码要么不断地创建和销毁线程,要么使用显式的同步和线程间通信机制来本质上挂起和重新启动线程。所有这些都是可能的,但它比通过支持非繁忙等待的单个线程安全队列进行通信要复杂得多。
有不同的版本。您可以使用单个线程从输入中获取项并触发工作线程,当要处理的项的数量超过可用工作线程的数量时,将其他工作线程或工作项排队。这只是生成器中的另一个复杂级别,并不会真正改变事情。
我不能说哪一个更有效率,尽管这可能是一个未知数。与总执行时间相比,执行时间上的任何差异都可能非常小,以至于它们是无关紧要的。对我来说,更重要的是我的程序是正确的和易于理解的。具有共享队列的简单生产者/消费者模型比我自己的使用大量显式同步的自定义分派器更容易编码、理解和证明是正确的。
发布于 2014-04-03 12:45:50
与多个使用者线程争用的代价是,它们必须在等待锁使用时阻塞。在您建议的模式服务于多个线程的情况下,线程在等待消费时仍然需要阻塞。只是他们在等待“单一消费者”,而不是等待一个简单的锁。由于“单一消费者”将比简单的锁更复杂,它的效率会更低,更容易出现bug。
https://stackoverflow.com/questions/22821235
复制相似问题