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

Go通道同步能否保证goroutine打印顺序?代码同步性验证

关于Go代码同步性的确认与分析

你的代码如下:

func main() {
    ch1 := make(chan bool)
    done := make(chan bool)

    go func() {
        fmt.Println("Two")
        ch1 <- true
    }()
    go func() {
        fmt.Println("One")
        <-ch1
        done <- true
    }()
    <-done
}

核心问题解答

你的代码完全可能出现先输出"Two"再输出"One"的情况,顺序错乱是必然存在的概率性问题,之前20次运行符合预期只是巧合。

原因很直接:Go runtime对goroutine的调度顺序是无规则的,两个goroutine启动后,谁先被执行完全由调度器决定:

  • 如果调度器先调度第一个goroutine:会先打印"Two",然后卡在ch1 <- true(此时没有goroutine接收这个值),直到第二个goroutine被调度,打印"One"、接收ch1的值,最后触发done结束main
  • 如果调度器先调度第二个goroutine:会先打印"One",卡在<-ch1,等第一个goroutine打印"Two"并发送值后,才会继续执行

修正方案

如果要确保严格的"One"→"Two"输出顺序,需要用channel明确控制执行流,让打印"Two"的goroutine等待打印"One"的信号:

func main() {
    ch := make(chan struct{})
    done := make(chan bool)

    // 等待信号再打印Two
    go func() {
        <-ch
        fmt.Println("Two")
        done <- true
    }()

    // 先打印One,再发信号通知
    go func() {
        fmt.Println("One")
        ch <- struct{}{}
    }()

    <-done
}

如果场景更简单,甚至可以去掉多余的goroutine直接同步执行;如果必须用goroutine,也可以用WaitGroup实现更清晰的等待逻辑:

import "sync"

func main() {
    var wg sync.WaitGroup
    wg.Add(1)

    go func() {
        defer wg.Done()
        fmt.Println("One")
    }()

    // 等One打印完再打印Two
    wg.Wait()
    fmt.Println("Two")
}

最佳实践

  • 非必要不要为了并行而强行拆分goroutine,简单顺序逻辑直接同步执行更高效
  • 用goroutine时必须明确同步依赖,通过channel或WaitGroup严格约束执行顺序
  • WaitGroup适合批量等待多个goroutine完成的场景,单依赖的简单场景用channel更轻量

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.04 03:12:34