如果从 Go 中的通道读取了值,如何发出信号

分享于2023年02月15日 concurrency go 问答
【问题标题】:How to signal if a value has been read from a channel in Go如果从 Go 中的通道读取了值,如何发出信号
【发布时间】:2023-02-06 23:48:48
【问题描述】:

我正在读取通过无限 for 放入通道 ch 的值。我想要某种方式来指示某个值是否已被读取和操作(通过 sq 结果),并在成功时将其添加到某种 counter 变量中。这样我就有办法检查我的频道是否已用完,以便我可以正确退出我的无限 for 循环。

目前无论是否读取值,它都在递增,因此导致它在 counter == num 时提前退出。我只希望它在对值进行平方时计算。

package main

import "fmt"

func main() {

    num := 5

    // Buffered channel with 5 values.
    ch := make(chan int, num)
    defer close(ch)

    for i := 0; i < num; i++ {
        go func(val int) {
            fmt.Printf("Added value: %d to the channel\n", val)
            ch <- val
        }(i)
    }

    // Read from our channel infinitely and increment each time a value has been read and operated upon
    counter := 0
    for {
        // Check our counter and if its == num then break the infinite loop
        if counter == num {
            break
        }
        val := <-ch
        counter++
        go func(i int) {
            // I'd like to verify a value was read from ch & it was processed before I increment the counter
            sq := i * i
            fmt.Println(sq)
        }(val)
    }
}

  • 无缓冲通道上的发送和接收是同步的。这些值在发送的那一刻就被接收到,并且没有“耗尽”通道,它不能包含任何值。
  • @JimB 所以如果我用 num 的值缓冲它。然后我如何发出信号表明所有值都已从通道中读取?我用缓冲版本更新了我的答案。我最终只是希望能够在从我的通道处理值时发出信号,这样我就可以发出信号表明初始 goroutines 已经完成了它们的工作。
  • 当没有更多值将通过关闭通道发送到通道时,您发出信号。我建议通过 Tour of Go,特别是 Concurrency 上的部分

【解决方案1】:
package main

import "fmt"

func main() {
    c := make(chan int)
    done := make(chan bool)

    go func() {
        for i := 0; i < 10; i++ {
            c <- i
        }
        close(c)
    }()

    go func() {
        for i := range c {
            fmt.Println(i)
            done <- true
        }
        close(done)
    }()

    for i := 0; i < 10; i++ {
        <-done
    }
}

在此示例中,done 通道用于表示已从 c 通道读取了一个值。从 c 读取每个值后,将在 done 通道上发送一个信号。 done 通道上的 main 函数块,在继续之前等待信号。这确保在程序终止之前处理了来自 c 的所有值。

【讨论】: