dongxin991209 2018-07-26 02:54
浏览 34
已采纳

为什么我的频道需要缓冲区?

I'm trying to learn Go and I'm using this tutorial.

I've written the following code,

var wg sync.WaitGroup

func foo(c chan int, someValue int) {
    defer wg.Done()
    c <- someValue * 5
}

func main() {
    fooVal := make(chan int)
    for i := 0; i < 10; i++ {
        go foo(fooVal, i)
        wg.Add(1)
    }

    wg.Wait() // Wait for all routines to complete
    close(fooVal) // close channel

    for item := range fooVal {
        fmt.Println(item)
    }
}

Here is my understanding so far,

  • I create a channel that receives ints
  • I create 10 subroutines, and I add 1 to the waitgroup so I can get them to sync later
  • I wait for the routines to complete
  • I close the channel so that it doesn't receive any more values
  • I loop through the values in the channel to print them

However, I get an error that says:

fatal error: all goroutines are asleep - deadlock!

I'm not sure what this means. My guess is that range tries to get a value from the channel but it doesn't have any. But that shouldn't be happening because I waited for all routines to complete and then I closed the channel.

What's going on?

The solution for this is to do something like make(chan int, 10) to give it a buffer, but I'm not sure what a buffer is or why I need it.

Also, I'm not sure what make does. I've used it to create a map as well. Is it just a constructor?

  • 写回答

2条回答 默认 最新

  • duankeng9477 2018-07-26 03:31
    关注

    The reason all of your goroutines are asleep is because by default a channel blocks it's goroutine on send until the value is received. See https://tour.golang.org/concurrency/2

    By default, sends and receives block until the other side is ready. This allows goroutines to synchronize without explicit locks or condition variables.

    A buffer resolves this by allowing a channel to 'hold' that many values without blocking. Think of a buffered channel as a bucket that can hold N items (where N is the buffer size, 10 in your case) in order to put more into the bucket, you need to wait for something to be removed (i.e. read). By default a channel is unbuffered, and it's value must be received before it will unblock it's sending goroutine.

    In your code you have goroutines attempting to put items into your unbuffered channel, so the first routine waits for the item it put into the channel to be read. But your channel will never empty until the range statement reads it, which will never fire until the channel empties and the goroutine finishes (because of wg.Wait()), which is a deadlock. Neither can proceed.

    With a buffer, the buffered channel tells your goroutines it's ok to finish without it's value being read (up to 10 items in your case) and so the waitgroup finishes, and the range statement reads all the values out as expected.

    As for make, thinking of it as a constructor is good enough, but know that it's only used for slices, channels and maps. Those are special types in go and can't be created like regular structs. (I believe it has to do with the fact that each of those acts generically, i.e. it can hold items of any specified type, and that's why make is needed, but I'm not 100% on that).

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站
  • ¥50 成都蓉城足球俱乐部小程序抢票
  • ¥15 yolov7训练自己的数据集
  • ¥15 esp8266与51单片机连接问题(标签-单片机|关键词-串口)(相关搜索:51单片机|单片机|测试代码)
  • ¥15 电力市场出清matlab yalmip kkt 双层优化问题
  • ¥30 ros小车路径规划实现不了,如何解决?(操作系统-ubuntu)
  • ¥20 matlab yalmip kkt 双层优化问题
  • ¥15 如何在3D高斯飞溅的渲染的场景中获得一个可控的旋转物体