好好爱自己!

why is this a deadlock in golang / waitgroup?

 

问题:

I'm not sure what I'm missing but I get a deadlock error. I'm using a buffered channel that I range over after all go routines complete. The channel has the capacity of 4 and I'm running 4 go routines so I'm expecting it to be "closed" automatically once it reaches the max capacity.

package main

import "fmt"
import "sync"

func main() {
    ch := make(chan []int, 4)
    var m []int

    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            ch <- m
            return
        }()
    }
    wg.Wait()

    for c := range ch {
        fmt.Printf("c is %v", c)
    }
}


You have two problems :

  • there's not enough place for all the goroutines as your channel is too small : when your channel is full, the remaining goroutines must wait for a slot to be freed
  • range ch is still waiting for elements to come in the channel and there's no goroutine left to write on it.

Solution 1 :

Make the channel big enough and, close it so that range stops waiting :

ch := make(chan []int, 5)
...
wg.Wait()
close(ch)

Demonstration

This works but this mostly defeats the purpose of channels here as you don't start printing before all tasks are done.

Solution 2 : This solution, which would allow a real pipelining (that is a smaller channel buffer), would be to do the Done() when printing :

func main() {
    ch := make(chan []int, 4)
    var m []int

    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func() {
            ch <- m
            return
        }()
    }
    go func() {
        for c := range ch {
            fmt.Printf("c is %v\n", c)
            wg.Done()
        }
    }()
    wg.Wait()
}

Demonstration

  •  
    why range ch is still waiting for elements if the channel is drained ? I assumed that once I send the 4th value the range reaches the end of "loop" so it should no longer wait for values. – hey Jul 7 '14 at 12:02 
  •  
    range waits until the channel is closed. That's how it works. This way you can launch a goroutine and have it still work if you push elements into the channel later. – Denys Séguret Jul 7 '14 at 12:04 
  •  
    thanks for the answer , though it's curious because I have an app that does just the same thing except it doesn't go into deadlock. It loops through some sql rows , launches go routines, I wg.Wait() after the for loop, range over the channel and display the results of each routine. There is no "close(ch)" operation. I can only assume that the program itself goes into deadlock but I don't get the error. – hey Jul 7 '14 at 12:10
  •  
    Concerning the 2nd solution I'm not sure I understand but it still goes into deadlock except that the error is not thrown in main ? – hey Jul 7 '14 at 12:13
  •  
    sorry ... I think I've got how it works after all. Anyway shouldn't wg.Done() be after fmt.Printf("c is %v\n", c) play.golang.org/p/Be8eEc6PMu – hey Jul 7 '14 at 12:41


posted @   立志做一个好的程序员  阅读(103)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
历史上的今天:
2016-04-21 浏览器加载外部js 的顺序,以及处理顺序。
2016-04-21 我也谈大型网站架构(一)
2015-04-21 Intergate flot with Angular js ——Angular 图形报表

不断学习创作,与自己快乐相处

点击右上角即可分享
微信分享提示