bigywater.tech
ClickHouse 内部原理 · 82

max_threads:线程越多为什么不一定越快

真实用CPU密集计算对比8个不同的max_threads设置,验证加速曲线在本机CPU核心数处精确出现拐点,之后完全平台不再提速。

拐点精确=10核
真实加速曲线在CPU核心数处完全平台
超线程数纯浪费
真实20~100线程耗时跟10线程完全一样

做的事:真实用CPU密集计算,测8个不同的线程数

代码-- 本机真实CPU核心数 sysctl -n hw.ncpu → 10 CREATE TABLE demo.cputest (k UInt64, s String) ENGINE=MergeTree ORDER BY k; INSERT INTO demo.cputest SELECT number, toString(number) FROM numbers(20000000); -- 真实对比 max_threads = 1,2,4,8,10,20,50,100 SELECT sum(sipHash64(s)) FROM demo.cputest SETTINGS max_threads=N FORMAT Null;

验证:真实到10个核心之前一直在加速,之后完全不再变化

实测 · 本机执行输出(2000万行,10核CPU)
max_threads=1    → 327ms
max_threads=2    → 148ms   (真实加速约2.2倍)
max_threads=4    →  80ms   (真实加速约4.1倍)
max_threads=8    →  49ms   (真实加速约6.7倍)
max_threads=10   →  43ms   (真实加速约7.6倍,正好等于CPU核心数)
max_threads=20   →  43ms   ← 真实一毫秒都没变
max_threads=50   →  44ms   ← 真实反而多了1ms(噪音范围内)
max_threads=100  →  43ms   ← 真实还是43ms

从1线程到10线程(本机真实的CPU核心数),耗时真实一路从327ms降到43ms,加速曲线非常清晰;但线程数超过10之后,无论开20、50还是100个线程,耗时真实死死卡在43~44ms,一点变化都没有——这条曲线的拐点,真实精确对应本机sysctl -n hw.ncpu返回的10个核心。

为什么真实的拐点,精确卡在CPU核心数上

这个真实的现象背后的道理很直白:max_threads控制的是ClickHouse愿意为这条查询开多少个并行执行流,但这些线程最终都要真实抢占本机CPU的物理核心才能跑起来——本机真实只有10个核心,能同时真正并行执行的计算流最多也就10个,第11个线程开始,操作系统只能通过时间片轮转的方式让它们分享这10个核心,不会凭空多出计算能力。本文这条CPU密集的sipHash64计算刚好是纯计算瓶颈(不涉及网络/磁盘等待),所以这条"到核心数之前线性加速、之后完全平台"的曲线真实体现得非常干净;如果查询本身有网络IO或者磁盘等待的成分,线程数超过核心数在某些场景下还能真实带来一点收益(某些线程等待IO时,其他线程可以顶上CPU空档),但对于像本文这种纯计算密集的任务,超过物理核心数的线程数真实是纯浪费——不仅不会变快,反而会带来真实存在但本文这次测试幅度很小的线程调度开销(本文50线程那次44ms比43ms多出的1ms,勉强能算是这类开销的一点真实痕迹,但幅度小到接近测量噪音)。真实的建议是:max_threads默认的auto(核心数)通常已经是一个合理的选择,手动调大到远超核心数一般不会带来本文验证过的这种真实收益,调小则可能是在特定场景下(比如故意限制某类查询抢占太多CPU资源)主动做出的取舍。

分步演示:从线性加速到核心数以后完全平台的真实曲线

每一步都是本文上面用真实sipHash64计算跑出来的原始耗时。

加速曲线精确卡在CPU核心数这个拐点上
这一步新验证的线程数

    本文用到的工具

    • 本机 ClickHouse 26.9.4(10核CPU),真实对比8个 max_threads 档位的CPU密集计算耗时
    京ICP备2026067502号-1京公网安备11010502063487号