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

Go并发操作中如何正确关闭channel以解决程序无法退出问题

修复方案

问题核心是:range遍历channel时会持续阻塞直到channel被关闭,原代码没有在所有goroutine完成写入后主动关闭channel,所以主协程会永久卡在遍历逻辑里。

正确的做法是用sync.WaitGroup监控所有发起的goroutine执行状态,等全部goroutine都完成向channel的写入操作后,再关闭channel,步骤如下:

  1. 引入sync标准库,初始化WaitGroup实例
  2. 每启动一个getLink goroutine前调用wg.Add(1)计数
  3. 在getLink函数中用defer wg.Done()标记当前goroutine执行完成
  4. 单独启动一个goroutine等待所有WaitGroup计数归零后执行close(ch)关闭channel

修改后完整代码

package main

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

var links = []string{
    "https://mcevik.com",
    "https://stackoverflow.com",
    "https://www.linkedin.com",
    "https://github.com",
    "https://medium.com",
    "https://kaggle.com",
}

func getLink(link string, ch chan string, wg *sync.WaitGroup) {
    // 函数退出时自动标记任务完成
    defer wg.Done()
    if res, err := http.Get(link); err != nil {
        ch <- err.Error()
    } else {
        ch <- fmt.Sprintf("[%d] - %s", res.StatusCode, link)
    }
}

func main() {
    ch := make(chan string, len(links))
    var wg sync.WaitGroup

    for _, link := range links {
        // 启动goroutine前新增计数
        wg.Add(1)
        go getLink(link, ch, &wg)
    }

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

    // 此时channel关闭后range循环会自动退出
    for msg := range ch {
        fmt.Println(msg)
    }
}

注意事项

  • 不能在启动所有goroutine后直接在主协程调用wg.Wait()再关闭channel,否则会发生死锁:主协程等所有goroutine写完,但是goroutine写channel时如果缓冲区满了会阻塞,主协程又没在读channel,就会互相卡住
  • 不要提前关闭channel,否则未完成的goroutine向已关闭的channel写入数据会直接触发panic

替代方案(无需关闭channel)

因为明确知道总共有len(links)条返回结果,也可以不用range遍历,直接循环固定次数读取channel,也能正常退出,写法更精简:

func main() {
    ch := make(chan string, len(links))

    for _, link := range links {
        go getLink(link, ch)
    }

    // 固定读取len(links)次,不需要关闭channel
    for i := 0; i < len(links); i++ {
        fmt.Println(<-ch)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 23:45:02