duagfgfn1981 2018-10-14 14:34
浏览 149
已采纳

如何从多个goroutine共享的单个通道读取

I have several goroutines writing to the same channel. If I use a buffered channel I can retrieve the input. However if use an unbuffered channel I can only read about half the values:

func testAsyncFunc2() {

    ch := make(chan int,10)

    fmt.Println("testAsyncFunc2")
    wg.Add(10)
    for  i :=0; i < 10; i++  {
        go sender3(ch, i)
        wg.Done()
    }

    receiver3(ch)

    close(ch)
    wg.Wait()
}

This is the receiver function:

func receiver3(ch chan int) {
    for {
        select {
        case <-ch:
            fmt.Println(<-ch)
        default:
            fmt.Println("Done...")
            return
        }
    }
}

Sender function:

func sender3(ch chan int, i int) {
    ch <- i
}

And the output:

testAsyncFunc 2 0 4 6 8 2 Done...

While I would expect to get back 10 numbers.

  • 写回答

2条回答 默认 最新

  • dqu92800 2018-10-14 14:41
    关注

    The code will return with an error if you not create buffer channels reason being the channel is closed before all the values sent on it.

    Do not close the channels and wait for the go routines to complete. If you want to close the channels, close when all the values send on the channel are received inside the receiver go routine.

    fmt.Println("testAsyncFunc2")
    for  i :=0; i < 10; i++  {
        wg.Add(1)
        go sender3(ch, i)
    }
    
    receiver3(ch)
    close(ch) // this will close the channels before all the values sent on it will be received.
    wg.Wait()
    

    One more thing to notice you have increased wait group counter to 10 while you are decreasing the counter after you launch the go routine inside the for loop which is wrong. You should decrease the wait group counter inside the sender go routine when it is finished its execution.

    func sender(ch chan int, int){
         defer wg.Done()
    }
    

    In the for loop the select default condition will run before all the values sent on the channel is received that's why all values send will not print. Since the loop will return when there is no value send on the channel.

    func receiver3(ch chan int) {
        for {
            select {
            case <-ch:
                fmt.Println(<-ch)
            default: // this condition will run when value is not available on the channel.
                fmt.Println("Done...")
                return
            }
        }
    }
    

    Create a go routine to close the channel and wait for the sender go routines to finish. So below code will wait for your all go routines to finish sending the values on channels and then it will close the channel:

    package main
    
    import (
        "fmt"
        "sync"
    )
    
    var wg sync.WaitGroup
    
    func main() {
        ch := make(chan int)
        fmt.Println("testAsyncFunc2")
        for i := 0; i < 10; i++ {
            wg.Add(1)
            go sender(ch, i)
        }
        receiver3(ch)
        go func() {
            defer close(ch)
            wg.Wait()
        }()
    }
    
    func receiver3(ch <-chan int) {
        for i := 0; i < 10; i++ {
            select {
            case value, ok := <-ch:
                if !ok {
                    ch = nil
                }
                fmt.Println(value)
            }
            if ch == nil {
                break
            }
        }
    }
    
    func sender(ch chan int, i int) {
        defer wg.Done()
        ch <- i
    }
    

    Output

    testAsyncFunc2
    9
    0
    1
    2
    3
    4
    5
    6
    7
    8
    

    Working Code on Go playground

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(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高斯飞溅的渲染的场景中获得一个可控的旋转物体