2

以下是 Java Concurrency in Practice 一书的节选,第 12.2 章性能测试,作者谈到了有界缓冲区实现的吞吐量。

图 12.1 显示了 4 路机器上的一些示例结果,使用的缓冲区容量为 1、10、100 和 1000。我们立即看到缓冲区大小为 1 会导致吞吐量非常低;这是因为每个线程在阻塞和等待另一个线程之前只能取得一点点进展。将缓冲区大小增加到 10 会有很大帮助,但增加超过 10 会带来收益递减。

一开始可能有点令人费解,添加更多线程只会稍微降低性能。原因很难从数据中看出,但在测试运行时在诸如 perfbar 之类的 CPU 性能计上很容易看出:即使有很多线程,也没有进行太多计算,大部分都花在阻塞和解除阻塞线程上. 因此,有足够的 CPU 空闲时间让更多线程执行相同的操作,而不会对性能造成太大影响。

但是,请注意从这些数据中得出的结论是,您始终可以向使用有界缓冲区的生产者-消费者程序添加更多线程。这个测试在模拟应用程序方面是相当人为的;生产者几乎不做任何工作来生成放置在队列中的项目,而消费者几乎不做任何工作来处理检索到的项目。如果真正的生产者-消费者应用程序中的工作线程做一些重要的工作来生产和消费项目(通常是这种情况),那么这种松弛就会消失,线程过多的影响可能会非常明显。该测试的主要目的是测量通过有界缓冲区进行的生产者-消费者切换对整体吞吐量施加的限制。

在此处输入图像描述

作者这里的cpu slack是什么意思?为什么随着线程数量的增加,吞吐量不会越来越下降?我没有遵循作者给出的关于在添加越来越多的线程时性能略有下降的推理,假设缓冲区大小的界限保持不变。

编辑:我能想到一个原因:因为在这种情况下,线程没有做任何实际工作,所以共享内存总线上流量增加的经典问题,由于线程的上下文切换导致的缓存未命中数并没有发挥主要作用随着越来越多的线程被添加。一旦线程开始做更多的工作,情况就会改变。这就是作者在第三段中试图表达的意思吗?

4

2 回答 2

1

没有诸如 CPU slack 之类的正式术语。作者的意思只是说 CPU 在做有意义的工作时没有充分利用,因为大部分时间都花在等待成功获取互斥锁上。作者将CPU的未使用容量称为CPU slack。

注意:相关代码测试多生产者/多消费者场景,生产者和消费者数量相等。

编辑:在后面的讨论中,他们讨论了添加更多线程的效果,如果 a) 线程几乎不做任何工作,并且 b) 对于每个生产或消费的项目,线程基本上占用了 CPU。我将尝试用一些稍微人为的场景来解释差异。

假设加锁主动占用1个时间单位,被动等待8个时间单位。被动等待不占用CPU。

案例1:生产者-消费者成本为1个时间单位。

所以我们目前占 CPU 时间的 2 个时间单位,另外还有 8 个时间单位的被动等待时间。所以我们有 8/10 个可用的 CPU 时间单位。

如果我们现在想将线程数加倍,我们需要额外容纳 2 个时间单位(1 个用于生产者-消费者的东西,1 个用于活动锁定时间)。这会消耗我们的可用 CPU 时间供应——但我们有足够的时间。

案例 2:生产者-消费者成本为 11 个时间单位。

所以我们目前占 CPU 时间的 11+1=12 个时间单位,另外还有 8 个时间单位的被动等待时间。所以我们有 8/20 个可用的 CPU 时间单位。

如果我们现在想将线程数加倍,我们需要额外容纳 12 个时间单位(11 个用于生产者-消费者的东西,1 个用于活动锁定时间)。这超出了可用的 CPU 时间单位。必须付出一些代价——所以等待时间会增加,吞吐量也会受到影响。

因此,在情况 2 中,实际工作量减少了新线程可用的时间量,从而增加了观察到的锁定争用对吞吐量的影响。如果他们在书中也包含了这个想象场景的数字,那就太好了。这将使他们的手摇论点更容易理解。

于 2013-09-15T06:07:36.497 回答
-1

我认为cpu slack是资源。根据维基百科的说法,如果现在开始工作,则指的是工作后剩余的时间。大量的 cpu slack 意味着大量的计算资源。当消费者/生产者做一些不平凡的事情时,cpu slack 会减少并影响吞吐量。

于 2014-09-12T05:44:55.383 回答