You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何初始基准测试中ExecutorService比协程快?[已解决]

更新

我犯了两个低级错误!

  • 在ExecutorService示例中仅提交了1个任务
  • 忘记等待任务完成

修正测试后,三个示例的延迟均约为190-200 ms/op。


基准测试说明

我使用kotlinx-benchmark(基于jmh)创建基准测试,对比协程与线程池处理阻塞调用的性能。

做此测试的理由:

  • 协程执行阻塞调用时会阻塞底层线程
  • 网络调用通常是阻塞的
  • 常规服务中需要处理百万级网络调用
  • 这种场景下使用协程能否获得收益?

测试场景与结果

我通过Thread.sleep(10) // 模拟10ms阻塞调用创建1000个调用,设置三个测试案例,结果如下:

Dispatchers.io

采用官方推荐的IO操作处理方式Dispatchers.IO:

@Benchmark
fun withCoroutines() {
    runBlocking {
        val coroutines = (0 until 1000).map {
            CoroutineScope(Dispatchers.IO).async {
                sleep(10)
            }
        }

        coroutines.joinAll()
    }
}

平均耗时:188.418 ms/op

固定线程池

Dispatcher.IO默认会创建64个线程(静态环境下数量不确定),因此我设置60个线程保证场景可比性:

@Benchmark
fun withExecutorService() {
    val executors = Executors.newFixedThreadPool(60)
    executors.submit { sleep(10) }
    executors.shutdown()
}

平均耗时:0.054 ms/op

线程池调度器

由于结果差异过大,我将上述线程池转换为协程调度器使用:

Executors.newFixedThreadPool(60).asCoroutineDispatcher()

平均耗时:206,260 ms/op


疑问
  1. 为何协程在此测试中表现异常糟糕?
  2. 使用limitedParallelism(10)选项后,协程性能提升至30ms/op。IO调度器默认线程数为64,是否说明协程调度器因过多上下文切换导致性能下降?但与线程池的性能差距仍较大。
  3. 我假设网络调用始终是阻塞的是否正确?ExecutorService与协程均通过底层线程调度执行,且不阻塞主线程,二者是否为直接竞品?

测试配置

运行jmh时使用如下配置:

@State(Scope.Benchmark)
@Fork(1)
@Warmup(iterations = 50)
@Measurement(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.AverageTime)

内容的提问来源于stack exchange,提问作者Mangat Rai Modi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 10:40:17