Go中遍历缓冲通道出现阻塞问题咨询
Go语言缓冲通道遍历阻塞问题分析与修复
原问题与阻塞原因
启动两个goroutine向缓冲通道写入数据后,for range遍历通道的代码一直阻塞,后续代码无法执行。
原代码如下:
results := []search.Book{} resultsStream := make(chan []search.Book, 2) defer close(resultsStream) // parallelize searches to optimize response time for _, src := range sources { go src.Search(bookName, resultsStream) } counter := 0 for sourceResults := range resultsStream { counter = counter + 1 results = append(results, sourceResults...) fmt.Println(counter) } fmt.Println("Never called")
程序输出:
1 2
阻塞原因:
Go语言中for range遍历通道时,会持续等待通道的新数据,直到通道被关闭才会退出循环。你代码里的defer close(resultsStream)要等到当前函数执行完毕才会触发,但函数卡在for range循环里永远走不到结尾,导致通道永远不会关闭,循环一直阻塞,后面的代码自然无法执行。
修复方案与代码说明
引入sync.WaitGroup等待所有goroutine完成写入后主动关闭通道,解决了阻塞问题:
var wg sync.WaitGroup results := []search.Book{} resultsStream := make(chan []search.Book, len(sources)) defer close(resultsStream) // parallelize searches to optimize response time for _, src := range sources { wg.Add(1) go src.Search(bookName, resultsStream, &wg) } wg.Wait() close(resultsStream) for sourceResults := range resultsStream { results = append(results, sourceResults...) } c.JSON(http.StatusOK, gin.H{ "results": results, })
关键修改点:
- 用
sync.WaitGroup跟踪所有goroutine:每个goroutine启动前调用wg.Add(1),src.Search执行完成后调用wg.Done()(需确保Search方法内部实现此步骤) - 调用
wg.Wait()等待所有goroutine完成数据写入,之后主动关闭通道,for range遍历完通道内所有数据后会自动退出循环 - 通道容量设为
len(sources),保证每个goroutine都能顺利写入数据,不会因通道满而阻塞
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

