在Java中,线程池大小通常被设置成CPU核心数+1,《Java Concurrency In Practise》8.2节中有这么一段话:
对于计算密集型的任务,在拥有N个处理器的系统上,当线程池的大小为N+1时,通常能实现最优的效率。(即使当计算密集型的线程偶尔由于缺失故障或者其他原因而暂停时,这个额外的线程也能确保CPU的时钟周期不会被浪费。)
btw: 不太熟悉Java,网上引用,没经过实践。
并发编程网上也有一篇相关的文章,要点如下:
如果是CPU密集型应用,则线程池大小设置为N+1
如果是IO密集型应用,则线程池大小设置为2N+1
最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目
线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程。
疑问:对于n核和2n线程的处理器有什么需要注意的地方?
以上都是引用自Java,Python方面的资料相对较少,所以想讨论一下。
由于CPython中GIL存在,Python同一时刻只能运行一个线程,所以这里不讨论计算型任务,只看IO型任务,Python线程池大小应该怎么设置才算合理?(IO最好的办法是采用异步,主要想讨论下不支持异步的情形)
天蓬老师2017-04-18 10:20:10
如何估算srv需要設定的進程數?
原則
每個進程佔用記憶體總和需要小於總記憶體
IO密集型
涉及到一些阻塞式網路通訊開銷,進程數可以開大一些,如配置成CPU 核數的3倍。如果業務中涉及的阻塞網路開銷很多,可以再適當加大進程數,例如 CPU核數的5倍甚至更高。
CPU密集型
也就是沒有外部網路IO開銷,或者沒有阻塞的網路IO開銷,例如使用非同步IO讀取網路資源,進程不會被業務程式碼阻塞的情況下,可以把進程數設定成和CPU核數一樣。
中心思想就是,你回應的瓶頸是在 io 還是在 CPU。
如果你的回應瓶頸是在 CPU
现在程序是 python 线程模式,你只能用到 N 个 CPU 中的一个,理论上你开多少个线程和开单线程是没有区别的,而且你只能跑的多核 CPU 中一个 CPU 100% 的利用率。而实际上,如果你开了多于 2 个线程,还会存在 CPU 调度的问题(上下文的保存等消耗),可能会比单核心略慢。
如果你的回應瓶頸是在 IO(如:網路 IO)
这就和其他语言一般的设置没有区别,主要是 比较 XN + 1(X 倍于 N 核心 CPU)先成为瓶颈还是 CPU 负载先成为瓶颈,因为如果成为了瓶颈之后,你再开多少线程对于程序的响应都是没有提高的(反而有可能下降)。