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

Goroutine为何偶尔出现高延迟?底层实现原因解析

问题描述

当创建100或1000个goroutine时,观测到偶尔会出现超过1ms的延迟。测试代码如下:

func main() {
    for i := 0; i < 100; i++ { // or use 1000
        go func() { testWaitRoutine() }()
    }

    time.Sleep(10 * time.Second)
}

func testWaitRoutine() {
    channl := make(chan int, 1)

    go func() {
        channl <- time.Now().Nanosecond()
        time.Sleep(3 * time.Second)
        channl <- time.Now().Nanosecond()
    }()

    _, secondTime := <-channl, <-channl
    nowTime := time.Now().Nanosecond()
    delay := nowTime - secondTime
    println(delay)
}

输出结果中存在少量微秒级和毫秒级的延迟数据,例如:

...
3000
338000
2000
...
1000
1000
72000
1000
...
2000
2000
1185000
1000
1000
...

硬件环境:2017款MBP和Windows 10系统均出现该现象。

疑问:为何goroutine有时会出现远高于稳定值的延迟?是什么底层实现导致的?

分析与解答
  • Goroutine调度的抢占机制限制:Go采用M:N调度模型,即便1.14版本引入了异步抢占,调度也无法做到绝对实时。当goroutine执行长时间系统调用(比如time.Sleep)或阻塞操作时,调度器会将M(操作系统线程)从P(逻辑处理器)解绑,但如果系统中P资源紧张、有大量goroutine等待调度,被唤醒的goroutine可能无法立即获得时间片,进而产生延迟。
  • 操作系统线程调度的干扰:Goroutine最终运行在操作系统线程上,而系统本身的线程调度存在不确定性。当系统中有其他进程、线程占用CPU资源时,操作系统可能临时挂起Go的M线程,切换到其他任务,这会直接导致goroutine执行被延迟,表现为观测到的毫秒级波动。
  • 系统定时器的精度限制:time.Sleep的精度依赖操作系统定时器,Windows默认定时器精度约1ms,macOS也有类似粒度。定时器到期时,操作系统唤醒对应线程的过程本身就可能存在延迟,尤其是系统负载较高时,这种延迟会被放大。
  • 通道操作的潜在竞争开销:虽然通道操作轻量,但大量goroutine同时进行通道收发时,可能触发调度器额外调度动作,或出现短暂的资源竞争,这也会引发少量延迟波动。

内容的提问来源于stack exchange,提问作者LoranceChen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 13:13:10