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

如何从多个Goroutine中获取返回值?解决通道阻塞问题

关于Goroutine返回值捕获与Worker Pools通道取值的问题

一、多Goroutine用sync.WaitGroup+无缓冲通道导致永久阻塞的问题

问题原因

你遇到的永久阻塞,大概率是以下两种情况:

  • 发送操作无对应接收:无缓冲通道的send操作必须在有receive操作等待时才能完成。如果主goroutine先调用wg.Wait()等待所有子goroutine结束,而子goroutine还在等待通道接收,就会形成死锁——主goroutine等子goroutine完成,子goroutine等通道接收。
  • 通道未关闭且接收次数不足:如果主goroutine只接收部分结果,剩余的子goroutine发送结果时会阻塞;或者接收完所有结果后未关闭通道,导致后续操作无意义阻塞。

正确实现示例

下面是适配多goroutine的写法,核心是在所有goroutine启动后接收结果,同时用单独goroutine等待任务完成后关闭通道:

package main

import (
	"fmt"
	"net/http"
	"sync"
)

func fetchBodyLength(url string, wg *sync.WaitGroup, resultChan chan<- int) {
	defer wg.Done()
	resp, err := http.Get(url)
	if err != nil {
		resultChan <- 0
		return
	}
	defer resp.Body.Close()
	resultChan <- int(resp.ContentLength)
}

func main() {
	urls := []string{
		"https://example.com",
		"https://golang.org",
		"https://github.com",
	}

	var wg sync.WaitGroup
	resultChan := make(chan int) // 无缓冲通道也可正常工作

	for _, url := range urls {
		wg.Add(1)
		go fetchBodyLength(url, &wg, resultChan)
	}

	// 单独goroutine等待所有任务完成后关闭通道
	go func() {
		wg.Wait()
		close(resultChan)
	}()

	// 遍历通道接收所有结果
	for length := range resultChan {
		fmt.Println("Body length:", length)
	}
}

二、Worker Pools示例中直接用fmt.Println(<-results)报错的问题

在Worker Pools示例中,直接调用fmt.Println(<-results)会报错或阻塞,原因如下:

  1. 通道未关闭:示例中results通道不会主动关闭,当所有任务完成后通道仍处于打开状态。如果主goroutine只执行一次<-results,取到一个结果后,程序会因无退出条件而阻塞;如果通道里暂时没有结果,会直接阻塞。
  2. 接收次数不匹配:示例中每个任务都会发送一个结果到results,若只接收一次,剩余结果会留在通道中,worker goroutine可能仍在运行(直到jobs通道关闭),最终导致程序无法正常退出。

如果想手动接收结果,需确保:

  • 接收次数与任务数量一致
  • 在所有worker完成后关闭results通道

修改后的主goroutine示例:

func main() {
	jobs := make(chan int, 5)
	results := make(chan int, 5)

	// 启动3个worker
	for w := 1; w <= 3; w++ {
		go worker(w, jobs, results)
	}

	// 发送5个任务
	for j := 1; j <= 5; j++ {
		jobs <- j
	}
	close(jobs)

	// 接收所有5个结果
	for a := 1; a <= 5; a++ {
		fmt.Println(<-results)
	}
	close(results)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 09:36:27