如何在不产生死锁的情况下使用一个缓冲通道和多个读取器?

huangapple go评论94阅读模式
英文:

How can I have one buffered channel and multiple readers without producing a deadlock?

问题

> 致命错误 所有的Go协程都处于休眠状态。死锁。

这是我尝试的代码。我调用了wg.Done()。缺少了什么?

package main

import (
    "fmt"
    "strconv"
    "sync"
)

func sender(wg *sync.WaitGroup, cs chan int) {
    defer wg.Done()
    for i := 0; i < 2; i++ {
        fmt.Println(i)
        cs <- i
    }
}

func reciever(wg *sync.WaitGroup, cs chan int) {
    x, ok := <-cs
    for ok {
        fmt.Println("Retrieved" + strconv.Itoa(x))
        x, ok = <-cs
        if !ok {
            wg.Done()
            break
        }
    }
}

func main() {
    wg := &sync.WaitGroup{}
    cs := make(chan int, 1000)
    wg.Add(1)
    go sender(wg, cs)
    for i := 1; i < 30; i++ {
        wg.Add(1)
        go reciever(wg, cs)
    }
    wg.Wait()
    close(cs)
}
英文:

> FATAL Error All go routines are asleep. Deadlock.

This is what I tried. I am calling wg.Done(). What is missing?

package main

import (
    &quot;fmt&quot;
    &quot;strconv&quot;
    &quot;sync&quot;
)

func sender(wg *sync.WaitGroup, cs chan int) {
    defer wg.Done()
    for i := 0; i &lt; 2; i++ {
        fmt.Println(i)
        cs &lt;- i
    }
}

func reciever(wg *sync.WaitGroup, cs chan int) {
    x, ok := &lt;-cs
    for ok {
        fmt.Println(&quot;Retrieved&quot; + strconv.Itoa(x))
        x, ok = &lt;-cs
        if !ok {
            wg.Done()
            break
        }
    }
}

func main() {
    wg := &amp;sync.WaitGroup{}
    cs := make(chan int, 1000)
    wg.Add(1)
    go sender(wg, cs)
    for i := 1; i &lt; 30; i++ {
        wg.Add(1)
        go reciever(wg, cs)
    }
    wg.Wait()
    close(cs)
}

答案1

得分: 1

wg.Wait之前,你应该关闭通道。
你所有的接收器都在等待通道中的数据。这就是为什么会出现死锁的原因。
你可以在sender函数的defer语句中关闭通道。
此外,如果从通道接收的第一次尝试不成功(因为通道已关闭),你需要调用wg.Done()

英文:

You should to close channel before wg.Wait.
All your receivers are waiting for data from channel. That's why you have deadlock.
You can close channel at defer statement of sender function.
Also you need to wg.Done() if the first attempt of receiving from channel was unsuccessful (because channel already closed)

http://play.golang.org/p/qdEIEfY-kl

答案2

得分: 0

有几件事情需要注意:

  1. 发送者完成后需要关闭通道。
  2. 在接收者中,使用 range 遍历通道。
  3. 不需要在等待组中添加 1,并在发送者中调用 Done。

请参考 http://play.golang.org/p/vz39RY6WA7

英文:

There are couple of things:

  1. You need to close the channel once sender is completed.
  2. In receiver, range over channel
  3. Don't need to add 1 to wait group and call Done in sender

Please refer to http://play.golang.org/p/vz39RY6WA7

huangapple
  • 本文由 发表于 2016年2月24日 20:19:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/35602060.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定