我正在编写一个具有多个生产者,单个消费者模型的应用程序(多个线程将消息发送到单个文件编写器线程)。

每个生产者线程包含两个队列,一个用于写入,一个用于消费者读出。消费者线程的每个循环,它遍历每个生产者并锁定该生产者的互斥体,交换队列,解锁,并从生产者不再使用的队列中写出。

在消费者线程的循环中,它在处理所有生成器线程后休眠指定的时间。我立刻注意到的一件事是,当我从1个生产者线程移动到2时,生产者将某些东西写入队列并返回的平均时间显着增加(减少5倍)。随着更多线程的添加,这个平均时间减少直到它的底部out - 10个生产者与15个生产者之间的时间差别不大。这可能是因为有更多的生产者要处理,生产者线程的互斥锁争用较少。

不幸的是,<!> lt; 5个生成器是应用程序的一个相当常见的场景,我想优化睡眠时间,以便无论有多少生成器,我都能获得合理的性能。我注意到,通过增加睡眠时间,我可以获得更低的生产者数量的性能,但是对于大型生产者计数的性能更差。

有没有其他人遇到过这个问题,如果有的话,你的解决方案是什么?我已经尝试使用线程数来缩放睡眠时间,但它似乎有点机器特定且非常反复试验。

有帮助吗?

解决方案

您可以根据生产者的数量选择睡眠时间,甚至可以根据某些动态方案调整睡眠时间。如果消费者醒来并且没有工作,则将睡眠时间加倍,否则将其减半。但是将睡眠时间限制在某个最小值和最大值。

无论哪种方式,你都在撰写更基本的问题。睡觉和轮询很容易正确,有时是唯一可用的方法,但它有许多缺点,而不是<!> quot;对<!>方式。

您可以通过添加信号量来指向正确的方向,只要生产者将项目添加到队列中,信号量就会递增,而当消费者处理队列中的项目时,信号量会递减。消费者只有在有待处理的物品时才会醒来,并且会立即醒来。

轮询队列可能仍然是一个问题。您可以添加一个新队列,该队列引用任何包含项目的队列。但它提出的问题是,为什么没有消费者处理的单个队列而不是每个生产者的队列。其他一切都是平等的,听起来像是最好的方法。

其他提示

我会建议您的消费者阻止生产者发出信号的状态,而不是睡觉。在符合posix的系统上,您可以使用pthread_cond。创建一个pthread_cond_t数组,每个生成器一个,然后创建一个在它们之间共享的数组。生产者首先发信号通知他们各自的条件变量,然后是共享变量。消费者等待共享条件,然后遍历数组的元素,对数组的每个元素执行pthread_cond_timed_wait()(使用pthread_get_expiration_np()获取<!>的绝对时间;现在<!>; )。如果等待返回0,则该生产者已写入数据。消费者必须在再次等待之前重新初始化条件变量。

通过使用阻塞等待,您可以最大限度地减少消费者不必要地锁定生产者的时间。您也可以使用信号量来完成此工作,如前面的答案中所述。在我看来,信号量与条件相比已经简化了语义,但是对于每次通过消费者循环处理的每个生成器,你必须小心地减少共享信号量。条件变量的优点是,如果在发出信号后重新初始化它们,您基本上可以像布尔信号量一样使用它们。

尝试使用您用于编程的语言查找阻止队列的实现。对于任意数量的生产者和一个消费者而言,只有一个队列就足够了。

对我而言,听起来你不小心通过让消费者线程在其他地方忙碌来引入一些缓冲,无论是睡觉还是做实际的工作。 (作为缓冲区的队列)也许在生产者端做一些简单的缓冲会减少你的争用。

您的系统似乎对生产者和消费者之间的锁争用非常敏感,但我很困惑为什么这样一个简单的交换操作会占用足够的CPU时间来显示在您的运行统计数据中。

你能展示一些代码吗?

编辑:即使没有工作要做,也许你正在锁定和交换队列?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top