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

Go语言通道问题:使用Select仅输出单个通道内容求助

解决Go Channels并发只输出单个结果的问题

嘿,我来帮你捋捋这个问题!你写的并发square函数逻辑本身没毛病,但问题出在主goroutine的处理上——要么是你只接收了其中一个通道的数据,要么是主goroutine跑得太快,没等另一个goroutine把数据发出来就直接退出了。

最直接的修正方案(适合少量goroutine场景)

如果就两个并发任务,最简单的方法就是在主函数里分别接收两个通道的值,这样主goroutine会一直阻塞,直到两个数据都被拿到:

package main

import "fmt"

func square(dat int, ch chan<- int) {
    ch <- dat * dat
}

func main() {
    resp1 := make(chan int)
    resp2 := make(chan int)

    go square(20, resp1)
    go square(10, resp2)

    // 依次等待两个通道的数据,拿到一个打印一个
    fmt.Println(<-resp1)
    fmt.Println(<-resp2)
}

运行这段代码,你就能看到400和100两个结果了。

进阶方案:用WaitGroup管理多goroutine

要是以后你要处理十几个甚至几十个并发goroutine,一个个写接收语句就太麻烦了,这时候用sync.WaitGroup来统一管理并发任务会更灵活:

package main

import (
    "fmt"
    "sync"
)

func square(dat int, ch chan<- int, wg *sync.WaitGroup) {
    defer wg.Done() // 任务完成时通知WaitGroup:我搞定啦
    ch <- dat * dat
}

func main() {
    resp1 := make(chan int)
    resp2 := make(chan int)
    var wg sync.WaitGroup

    wg.Add(2) // 告诉WaitGroup要等待2个goroutine完成
    go square(20, resp1, &wg)
    go square(10, resp2, &wg)

    // 启动一个小goroutine,等所有任务完成后关闭通道(避免后续接收阻塞)
    go func() {
        wg.Wait()
        close(resp1)
        close(resp2)
    }()

    // 遍历通道接收数据
    for val := range resp1 {
        fmt.Println(val)
    }
    for val := range resp2 {
        fmt.Println(val)
    }
}

你的代码只输出单个结果的原因分析

大概率是这两种情况:

  • 你在主函数里只写了一次通道接收(比如只写了fmt.Println(<-resp1)),主goroutine拿到这个值后就直接退出了,另一个square的goroutine还没来得及把数据发送到通道,程序就被强制终止了;
  • 即使你写了两次接收,但主goroutine在接收第一个值后因为其他逻辑提前退出了(不过这种情况比较少见)。

另外补充个知识点:你用的是无缓冲通道,ch <- dat*dat会一直阻塞,直到有goroutine来接收这个值。如果主goroutine不接收,square的goroutine会一直卡着,但主goroutine一旦退出,整个程序就直接结束,卡着的goroutine也会被强制终止。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:55:50