golang中缓冲通道上并发读取的冲突?

时间:2017-03-02 21:15:58

标签: go channel goroutine

我有一个缓冲的通道,由多个(本例中为4个)例程读取。

queue := make(chan string, 10000) // a large buffered channel

每个go例程都会检查通道中可用元素的数量并对其进行处理。

for i :=0; i< 4; i++{ // spun 4 go routines
    go func() {
        for {
            for elem := range queue {
                // do something with the elem from the channel
            }
         }
     }
  }

多个go例程会在读取时发生碰撞吗?换句话说,不同的go例程可以在通道中抓取相同的元素,或者当一个例程正在读取缓冲区时,另一个例程已经读取并处理了一些元素吗?如何在常规阅读的同时阻止其他常规程序阅读?

2 个答案:

答案 0 :(得分:5)

简单回答:不。放置在Go通道上的元素只能读取一次,无论有多少goroutine同时尝试读取通道,无论通道是否被缓冲,这都适用。两个不同的goroutine都不可能读取一个元素,除非该元素多次发送到通道。就通道语义而言,缓冲唯一能做的就是消除了读写同步发生的必要性。

答案 1 :(得分:1)

  

换句话说,不同的go例程可以在通道中抓取相同的元素,或者当一个例程正在读取缓冲区时,另一个例程已经读取并处理了一些元素吗?

...都能跟得上

我认为误解是非阻塞和线程安全概念之间的区别。

非阻塞(缓冲)频道

  

仅在缓冲区已满时才发送到缓冲的通道块。

缓冲通道就像它说有缓冲区来存储一些项目。它允许读取goroutine进行读取而无需等待写入goroutine将项目放入通道,条件已经写入通道。如果一个未缓冲的通道它只能包含单个项目,那么它需要在撤回写入的项目之前阻止写入通道。 “阻塞/非阻塞”概念与“线程安全”概念无关,非阻塞并不意味着线程安全。

Go频道的线程安全

Go渠道在所有可用的使用方式中都是线程安全的。 Channel是一种引用类型,因此一旦分配了make通道,就可以通过值传递,因为它具有指向单个内存槽的隐式指针。显然包含在频道项中永远不会被复制,并且无法读取两次。