通道(channel)能够在多次读取时保持一个值吗?

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

Can go channel keep a value for multiple reads

问题

我理解一个通道的常规行为是在读取后会清空。有没有办法在多次读取时保留一个非缓冲通道的值,而不会将值从通道中删除?

例如,我有一个 goroutine 为多个下游 goroutine 生成单个数据供其使用。我不想创建多个通道或使用缓冲通道,因为这将要求我复制源数据(我甚至不知道需要多少份副本)。实际上,我希望能够像下面这样做:

main{
   ch := make(ch chan dType)

   ch <- sourceDataGenerator()
   for _,_ := range DynamicRange{
      go TargetGoRoutine(ch)
   }
   close(ch)       // 希望这将删除值和通道
}
func(ch chan dType) TargetGoRoutine{
   targetCollection <- ch    // 希望在读取后保留通道值
}

编辑
有人认为这是一个重复的问题。也许是,但不确定。这里的解决方案似乎很简单,正如 n-canter 指出的那样。它只需要每个 goroutine 在使用后通过将数据放回通道来“回收”数据。没有一个所谓的“重复”提供了这个解决方案。这是一个示例:

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

英文:

I understand the regular behavior of a channel is that it empties after a read. Is there a way to keep an unbuffered channel value for multiple reads without the value been removed from the channel?

For example, I have a goroutine that generates a single data for multiple down stream go routines to use. I don't want to have to create multiple channels or use a buffered channel which would require me to duplicate the source data (I don't even know how many copies I will need). Effectively, I want to be able to do something like the following:

main{
   ch := make(ch chan dType)

   ch &lt;- 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 &lt;- ch    // want to keep the channel value after read
}

EDIT
Some feel this is a duplicate question. Perhaps, but not sure. The solution here seems simple in the end as n-canter pointed out. All it needs is for every go routine to "recycle" the data by putting it back to the channel after use. None of the supposedly "duplicates" provided this solution. Here is a sample:

package main
import (
  &quot;fmt&quot;
  &quot;sync&quot;
)

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

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

   c &lt;- &quot;Original&quot;
   wg.Wait()
   fmt.Println(&lt;-c)
}

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

答案1

得分: 2

你可以在读取后将值重新添加到通道中,但是这样所有的goroutine都会按顺序读取共享值,而且你还需要一些同步原语来防止最后一个goroutine阻塞。

据我所知,唯一可以使用单个通道进行广播的情况是关闭它。在这种情况下,所有的读取者都会收到通知。

如果你不想复制大量数据,也许最好使用一些全局变量。但是要小心使用,因为它违反了Go语言的规则:“不要通过共享内存来通信;通过通信来共享内存”。

还可以参考这个问题:https://stackoverflow.com/questions/36417199/how-to-broadcast-message-using-channel

英文:

You may readd value back to the channel after reading, but then all your gouroutines will read shared value sequentially and also you'll need some synchronization primitives for last goroutine not to block.

As far as I know the only case when you can use the single channel for broadcasting is closing it. In this case all readers will be notified.

If you don't want to duplicate large data, maybe you'd better use some global variable. But use it carefully, because it violates golang rule: "Don't communicate by sharing memory; share memory by communicating."

Also look at this question https://stackoverflow.com/questions/36417199/how-to-broadcast-message-using-channel

huangapple
  • 本文由 发表于 2017年3月25日 08:37:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/43011220.html
匿名

发表评论

匿名网友

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

确定