douliaodun9153 2019-02-14 06:27
浏览 44
已采纳

如何使用频道?

I have a function which takes an int array and dumps them in a channel.

func Dump(a []int, ch chan int) {
    for i := range a {
        ch <- i
    }
    close(ch)
}

This main doesn't build:

func main() {
    ch := make(chan int)
    arr := []int{1, 2, 3, 4, 5}
    Dump(arr, ch)
    for i := range ch {
        fmt.Printf("Got %v
", i)
    }
}

throws this error:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.Dump(0xc000078f48, 0x5, 0x5, 0xc00006e060)
        /Users/300041738/go-workspace/src/test.go:7 +0x43
main.main()
        /Users/300041738/go-workspace/src/test.go:15 +0x9b
exit status 2

However, this builds:

func main() {
    ch := make(chan int)
    arr := []int{1, 2, 3, 4, 5}
    go Dump(arr, ch)
    for i := range ch {
        fmt.Printf("Got %v
", i)
    }
}

Why do I have to write go infront of Dump? I don't wish to dump the contents of the array asynchronously.

  • 写回答

3条回答 默认 最新

  • drdyszuy488152 2019-02-14 15:31
    关注

    The root of your problem - when you writing to unbuffered channel it's locked until someone read the value from the channel. For unbuffered channel - after each write operation you have to do one read operation. Else your second write operation will be locked until someone read the first value. In your first example, it will never happen.

    To illustrate:

    1. Dump() function invoked
    2. Running the first iteration of for loop
    3. Write i value to the channel
    4. Running the second iteration of for loop
    5. Trying to write the next i value to the channel, but it locks, nobody has read the first value.
    6. As all work is done in the single main goroutine the entire app is locked. Deadlock in the result.

    This happens when adding the goroutine usage (go Dump(arr, ch)):

    1. Dump() function invoked in the separate goroutine
    2. Running the first iteration of for loop
    3. Write i value to the channel
    4. Running the second iteration of for loop
    5. Trying to write the next i value to the channel, but it locks, nobody has read the first value.
    6. Goroutine is locked (where we running Dump()), but we have the main goroutine and go scheduler switches the control to the main goroutine.
    7. It means this line is actually executed for i := range ch. And it finally reads the first value!
    8. Now Dump() goroutine is unlocked and it's possible to write the second value.
    9. The control will be passed between two goroutines until all work is done.

    Note, the exact order of execution can differ (based on the logic of go scheduler). To play with it, you can add print into Dump() function for the case with go Dump(arr, ch):

    func Dump(a []int, ch chan int) {
        for i := range a {
            fmt.Printf("Write %v
    ", i)
            ch <- i
        }
        close(ch)
    }
    

    You will see that Write and Got messages will intermix.

    It's hard to provide a solution for your answer because it's a sandbox example and the channel is not needed there in reality.

    By using buffered channel, let's say with size n, you can do n writes without locking and reads. I would recommend you to review the basics of Go channels.

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

报告相同问题?

悬赏问题

  • ¥15 stm32流水灯+呼吸灯+外部中断按键
  • ¥15 将二维数组,按照假设的规定,如0/1/0 == "4",把对应列位置写成一个字符并打印输出该字符
  • ¥15 NX MCD仿真与博途通讯不了啥情况
  • ¥15 win11家庭中文版安装docker遇到Hyper-V启用失败解决办法整理
  • ¥15 gradio的web端页面格式不对的问题
  • ¥15 求大家看看Nonce如何配置
  • ¥15 Matlab怎么求解含参的二重积分?
  • ¥15 苹果手机突然连不上wifi了?
  • ¥15 cgictest.cgi文件无法访问
  • ¥20 删除和修改功能无法调用