你有没有遇到过这种情况:程序单线程跑得飞快,一加上多线程反而更慢了?内存占用还蹭蹭涨。这可不是玄学,而是你的多线程性能没经过真实检验。这时候,基准测试就成了照妖镜。
为什么需要专门测多线程?
多线程不是“开越多越快”的魔法开关。操作系统调度、CPU核心数、缓存争用、锁竞争,都会影响实际表现。比如你在写一个日志处理工具,原本串行处理10个文件要5秒,你心想:“我搞个5个线程并行处理,岂不是1秒搞定?”结果一跑发现花了6秒——因为线程频繁抢同一个写日志的锁,大家排队等着,反而更慢。
怎么才算靠谱的基准测试?
别拿System.currentTimeMillis()前后掐一下就算完事。Java里可以用JMH(Java Microbenchmark Harness),它会自动帮你预热JVM、隔离测试环境、多次采样取平均值。其他语言也有类似工具,比如Python的pyperf,Go自带的testing.B。
下面是一个简单的JMH示例:
@Benchmark
@Threads(4)
public void measureThroughput(Blackhole blackhole) {
<strong>int result = 0;</strong>
for (int i = 0; i < 1000; i++) {
result += i;
}
blackhole.consume(result);
}
这个注解@Threads(4)就表示用4个线程并发执行这段代码,JMH会统计吞吐量、平均耗时等指标。你可以分别测1、2、4、8个线程下的表现,画个折线图,一眼看出“最佳并发点”在哪。
关注什么指标?
吞吐量(每秒处理多少任务)当然重要,但也要看延迟波动、CPU使用率和GC频率。有时候线程开多了,吞吐上去了,但个别请求卡了几百毫秒,用户体验照样崩。就像早高峰地铁,人太多反而挤不上去,整体通行效率下降。
避免常见坑
别在测试时开着IDE、浏览器一堆标签,这些都会抢资源。最好在干净的环境下跑,或者至少保持一致。还有,别忘了关闭不必要的后台程序,比如自动同步的网盘、频繁弹通知的聊天软件。
另外,共享变量要小心。多个线程读写同一个变量,如果不加同步,结果可能错得离谱。但加锁又可能成为瓶颈。这时候可以试试无锁结构,比如AtomicInteger,或者用ThreadLocal避免竞争。
真实场景更重要
模拟数据尽量贴近真实。比如你做的是电商下单系统,那就按真实订单大小和并发用户数来压测。别拿10条测试数据就说“支持高并发”,那没意义。就像试车不能只在空地转圈,得上真实路况。