在调用外部接口时通过 CompletableFuture.supplyAsync
异步调用,该方法默认将任务提交到全局唯一的 ForkJoinPool,而它的并行度可以受
java.util.concurrent.ForkJoinPool.common.parallelism
影响。
本实验的目的是探究在异步请求快响应(~= 1ms)时,并行度对整体性能的影响。
实验设置
真实场景:
- 每次请求约调用接口 200 次
- 每次接口请求约 1ms 完成
当然由于接受并发请求,同时会接收多个请求,暂不纳入考虑。bench 代码如下:
List<Future> futures = new ArrayList<>(); |
实验环境
- OS: Mac, 8C, 16G
- Java version: JDK 11.0.2, OpenJDK 64-Bit Server VM, 11.0.2+9
- Bench 框架:JMH
- JMH 调用参数:
java -jar target/benchmarks.jar -i 5 -bs 50 -f 3
实验结果
实验结果如下图:
- 图中的并行度分别为 1, 2, 4, 8, 16, 32, 64, 128, 256
- 图中的 x 轴间隔是 log 过后的结果,可以看到两点的 x 轴距离相等
- 最左边的点
parallelism = 1
时,ForkJoinPool 会为每个提交的任务创建一个线程 - 第二个点代表
parallelism = 2
,此时最多运行两个线程,预期的时间为1 * 200 50 / 2 = 5000ms
实际开销6610
,多出的猜测是线程创建和切换 - 并行度翻倍后,平均时间大概减少一半,但随着并行度的增大(>8),减少的时间慢慢就小于一半了。
- 最后即使
parallelism > 200
,也没办法达到完全并行(1ms)的状态。
大致结论:并行度越大效果越好,但 overhead 也会越来越大。