Qt 中的最佳生产者/消费者线程模式

Posted

技术标签:

【中文标题】Qt 中的最佳生产者/消费者线程模式【英文标题】:Optimal producer/consumer thread pattern in Qt 【发布时间】:2021-07-18 15:49:44 【问题描述】:

我已经使用 Qt 线程实现了生产者/消费者模式。多个生产者线程生成由消费者组合的数据。使用信号/插槽和排队连接来实现通信。只要消费者能够比生产者线程产生数据的速度更快地消费数据,这就可以正常工作。

我的代码很难扩展。特别是增加生产者的数量很容易,但很难产生多个消费者线程。

现在,当在具有大量内核的 CPU/系统上运行软件时,问题就开始了。在这种情况下,我使用更多线程来生成数据。有时可能会发生(取决于数据生成的复杂性)消费者无法及时处理生成的数据。然后 Qt 事件队列中的事件迅速填满,内存消耗急剧增加。

我可以通过使用阻塞队列连接来解决这个问题。然而,这并不允许 CPU 满负荷,因为生产者倾向于在每次数据发射后不必要地等待消费者。

在非 Qt 软件中,我将使用具有固定大小的队列/邮箱/环形缓冲区,使生产者休眠,直到消费者释放该容器中的空间。这种机制限制了内存消耗并允许最佳的 CPU 负载。

但是我找不到使用 Qt 类的等效解决方案。事件队列是全局的,没有大小属性​​。有没有一种 Qt 方法可以最佳地解决这个问题?如果没有,我可以使用 STL 类来以我的方式耦合 (Q) 线程吗?

【问题讨论】:

【参考方案1】:

我认为在这种情况下您应该放弃使用 Qt,因为虽然事件处理速度非常快,但它显然不是为针对多核的 HPC 工作负载而设计的(因为集中的顺序事件队列)。所以我认为你应该使用快速的原子多生产者/多消费者 (MPMC) 队列。虽然您可能可以在此基础上编写一个 Qt 事件层,但我不确定这在性能方面是否是一个好主意。另一种解决方案是使用可变大小的块来减少事件的数量(在生产者和消费者之间使用反馈循环)。请注意,考虑到您的工作负载,最好考虑使用基于任务的运行时(已知可以很好地扩展)。

如果您正在寻找一个快速的 MPMC 队列,Boost (boost::lockfree::queue) 提供的队列不是很快,但这通常已经足够了。我所知道的最好的之一是this one。它基于一篇研究论文并用于大型游戏。 This one 在特定情况下在我的机器上稍快一些,并且更灵活,但是在使用它时应该非常小心,因为并不总是能确保一致性(即阅读文档)。请注意,线程库在队列的选择中应该无关紧要。

【讨论】:

我想提升队列应该足够了,我会尝试一下。我仍然对 Qt 解决方案的不稳定程度感到惊讶。建议在任何地方使用事件队列进行线程间通信。但是当仔细观察时,很明显它根本无法扩展,即使是具有可变复杂性的计算也不能总是安全地实现。奇怪的是 Qt 甚至没有提供基本的环形缓冲区或队列大小属性。这应该没什么大不了的。用于嵌入式系统的框架令人失望!

以上是关于Qt 中的最佳生产者/消费者线程模式的主要内容,如果未能解决你的问题,请参考以下文章

qt 插槽中的信号失败

java中的多线程的实现生产者消费者模式

161212并发编程中的关于队列

QT 信号量QSemaphore的使用

生产者消费者简单实现(转载)

生产者消费者模式的简单实现