Golang通道是否可以保留值供多次读取?

4
我了解通道的常规行为是在读取后清空。是否有一种方法可以保留未缓冲通道值以进行多次读取,而不会从通道中删除该值?
例如,我有一个goroutine生成单个数据供多个下游goroutines使用。我不想创建多个通道或使用缓冲通道,这将要求我复制源数据(我甚至不知道需要多少份副本)。实际上,我想能够执行以下操作:
main{
   ch := make(ch chan dType)

   ch <- sourceDataGenerator()
   for _,_ := range DynamicRange{
      go TargetGoRoutine(ch)
   }
   close(ch)       // would want this to remove the value and the channel
}
func(ch chan dType) TargetGoRoutine{
   targetCollection <- ch    // want to keep the channel value after read
}

编辑 有人认为这是一个重复的问题。也许是,但不确定。最后,像 n-canter 指出的那样,这里的解决方法似乎很简单。所有它需要的就是每个Go协程在使用完数据后将其放回通道中进行“回收”。没有任何所谓的“重复”提供了这种解决方案。以下是一个示例:

package main
import (
  "fmt"
  "sync"
)

func main() {
 c := make(chan string)
 var wg sync.WaitGroup
    wg.Add(5)

 for i := 0; i < 5; i++ {
    go func(i int) {
        wg.Done()
        msg := <-c
        fmt.Printf("Data:%s, From go:%d\n", msg, i)
        c <-msg

    }(i)
}

   c <- "Original"
   wg.Wait()
   fmt.Println(<-c)
}

https://play.golang.org/p/EXBbf1_icG


一个非缓冲通道不会保存任何值。那么将同一个值多次添加到缓冲通道中呢? - JimB
这是一个潜在的解决方案,但正如我所提到的,我更喜欢不必输入多个值。这是因为a)我真的不知道我需要多少个。所以我必须额外输入;b)数据相当大,不想重复太多:( - Bruce
听起来你只是想使用通道作为单个值周围的互斥体,那么为什么不直接使用互斥锁呢? - JimB
JimB,我可以使用互斥锁/全局变量,但由于存在多个源/目标场景,管理起来相当困难。 - Bruce
jfly,我查看了你的链接,但它们似乎都涉及常规通道行为。在这里找不到我要找的内容:( - Bruce
1个回答

2
您可以在读取后将值重新添加到通道中,但是然后所有的goroutine都会按顺序读取共享值,而且您还需要一些同步原语来使最后一个goroutine不被阻塞。
据我所知,唯一可以使用单个通道进行广播的情况是关闭它。在这种情况下,所有读者都将收到通知。
如果您不想复制大型数据,则最好使用一些全局变量。但是请小心使用,因为它违反了golang规则:“不要通过共享内存进行通信;通过通信共享内存。”
还请参阅这个问题 如何使用通道广播消息

我觉得这是目前为止最好的解决方案。有一点重复,但至少没有额外的重复 - 我不必创建比我需要的更多。谢谢! - Bruce

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接