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

如何非阻塞等待所有Go协程执行完成?附代码及输出疑问

问题分析与解决方案

你的代码核心问题是main goroutine没有等待所有子协程执行完毕就提前退出了,同时通道的设计也存在不合理之处,导致协程无法正常完成执行。我们一步步拆解问题:

为什么当前代码输出不完整?

  1. main函数提前终止:Go程序的生命周期由main goroutine决定,一旦main执行到fmt.Println("Done...")后结束,所有后台运行的子协程会被强制终止,所以你看不到后续的Done with loop输出。
  2. 通道缓冲与接收逻辑不匹配:你创建的ok通道缓冲只有1,当第二个及以后的协程尝试发送true时,会因为通道已满而阻塞;而main循环里的select大部分时候走default分支,并没有持续接收通道信号,导致阻塞的协程永远无法完成。
  3. 用time.Sleep控制流程不可靠:靠sleep来同步协程是非常糟糕的实践,实际场景中协程的执行时间是不确定的,这种方式完全无法保证同步正确性。

最优解决方案:使用sync.WaitGroup

Go标准库提供的sync.WaitGroup是专门用于等待多个goroutine完成的工具,代码简洁且可靠:

package main

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

func main() {
	var wg sync.WaitGroup
	fmt.Println("Starting...")

	for i := 0; i <= 3; i++ {
		wg.Add(1) // 每启动一个协程,等待计数器+1
		fmt.Println("Loop: ", i)
		// 传递循环变量副本,避免协程共享同一个变量地址的陷阱
		go func(i int) {
			defer wg.Done() // 协程执行完毕,计数器-1(defer确保panic时也会执行)
			long(i)
		}(i)
	}

	wg.Wait() // 阻塞等待所有协程完成,直到计数器归0
	fmt.Println("Done...")
}

func long(i int) {
	fmt.Println("Inside long: ", i)
	time.Sleep(3 * time.Second)
	fmt.Println("Done with loop: ", i)
}

关键说明:

  • wg.Add(n):在启动协程前调用,告诉WaitGroup需要等待n个协程。
  • wg.Done():协程执行完毕时调用,减少等待计数;用defer绑定可以确保无论协程正常结束还是发生panic,都会正确通知WaitGroup。
  • wg.Wait():阻塞main goroutine,直到所有协程都调用了Done(),计数器归0后才继续执行。

备选方案:用通道实现等待

如果你一定要用通道来完成同步,可以调整通道缓冲大小并在main中主动接收所有协程的完成信号:

package main

import (
	"fmt"
	"time"
)

func main() {
	// 通道缓冲大小等于协程数量,避免协程发送时阻塞
	ok := make(chan bool, 4)
	fmt.Println("Starting...")

	for i := 0; i <= 3; i++ {
		fmt.Println("Loop: ", i)
		go long(ok, i)
	}

	// 循环接收所有协程的完成信号
	for i := 0; i <= 3; i++ {
		<-ok
	}

	fmt.Println("Done...")
}

func long(c chan bool, i int) {
	fmt.Println("Inside long: ", i)
	time.Sleep(3 * time.Second)
	fmt.Println("Done with loop: ", i)
	c <- true
}

关键说明:

  • 将通道缓冲设置为协程总数(4),确保每个协程发送信号时不会阻塞。
  • main中通过循环接收4次通道数据,确保所有协程都完成后才继续执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:55:51