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

Go协程执行行为疑问:调度顺序与GOMAXPROCS设置困惑

Go Goroutine 相关疑问解答

我正在阅读《Go in Action》一书,对其中goroutine(协程)部分存在困惑,针对以下代码及输出有两个技术疑问:

package main

import (
    "fmt"
    "runtime"
    "sync"
    "time"
)

var counter int = 0
var wg sync.WaitGroup
var mtx sync.Mutex

func main() {
    wg.Add(2)

    runtime.GOMAXPROCS(1)

    go incCounter("A")
    go incCounter("B")

    wg.Wait()
    fmt.Println(counter)
}

func incCounter(prefix string) {
    fmt.Println("Started thread ", prefix)
    defer wg.Done()
    mtx.Lock()
    {
        fmt.Println("Incrementing counter from ", prefix)
        counter = counter + 1
        fmt.Println("Passing to another thread")
        runtime.Gosched()
        for i := 1; i < 100; i++ {
            time.Sleep(1 * time.Second)
            fmt.Println("Thread still executing ", prefix)
        }
    }
    mtx.Unlock()
}

输出如下:

Started thread  B
Incrementing counter from  B
Passing to another thread
Started thread  A
Thread still executing  B
Thread still executing  B
Thread still executing  B
Thread still executing  B

疑问:

  1. 代码中先启动goroutine A,为何实际先执行goroutine B?
  2. 已将runtime.GOMAXPROCS设置为1,goroutine B调用runtime.Gosched()后,因mtx处于锁定状态,goroutine A需等待解锁,但输出看似两个goroutine在并行执行,这是否符合预期?

解答:

问题1:先启动A却先执行B的原因

Go的goroutine调度器不保证goroutine的启动顺序和执行顺序一致。调用go incCounter("A")只是将该goroutine加入待执行队列,此时main goroutine会继续执行go incCounter("B")。调度器会根据自身策略(如当前goroutine状态、队列优先级等)选择下一个执行的goroutine,因此先启动的A不一定先被调度,B先执行是完全正常的,这是goroutine调度不确定性的体现。

问题2:GOMAXPROCS=1下的执行是否符合预期

这完全符合预期,并非真正的并行执行:

  • 当goroutine B调用runtime.Gosched()时,会主动让出当前CPU时间片,调度器切换到goroutine A执行。
  • 但goroutine A执行到mtx.Lock()时,发现锁已被B持有,会进入阻塞状态,此时调度器会重新切回goroutine B继续执行(B只是主动让出时间片,并未被阻塞,仍处于可执行状态)。
  • 输出里的Started thread A是A被调度后执行的第一行打印,之后因锁阻塞,调度器切回B执行循环打印,看起来像“并行”,但实际是在单个CPU核心上的并发调度切换,并非真正意义上的并行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 06:25:04