简体   繁体   English

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

[英]Collision on concurrent read on buffered channel in golang?

I have a buffered channel that are read by multiple (4 in this example) go routines. 我有一个缓冲的通道,可以通过多个(在此示例中为4)go例程读取。

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

Each go routine checks the number of elements available in the channel and process them all. 每个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
            }
         }
     }
  }

Will multiple go routines collide on the reads? 多个go例程会在读取时发生冲突吗? In other words, could different go routine grab the same elem in the channel, or while one go routine is reading the buffer, the other go routines already read and processed some of the elements? 换句话说,不同的go例程可以在通道中捕获相同的元素,还是当一个go例程正在读取缓冲区时,另一个go例程已经读取并处理了某些元素? How to block other go routines from reading while one go routine is reading? 如何在阅读一个go例程的同时阻止其他go例程读取?

Simple answer: no. 简单的回答:不。 Elements placed on a Go channel can only be read once, regardless of how many goroutines are trying to read off the channel at the same time, and that applies regardless of whether the channel is buffered or not. 放置在Go通道上的元素只能被读取一次,无论有多少goroutine试图同时读取该通道,并且无论通道是否被缓冲,该元素都适用。 There's no possibility that an element will be read by two different goroutines unless that element was sent to the channel more than once. 除非一个元素多次发送到通道,否则不可能被两个不同的goroutine读取该元素。 The only thing that buffering does, with regards to channel semantics, is remove the necessity for the read and write to occur synchronously. 关于通道语义,缓冲所做的唯一一件事就是消除了读写同步发生的必要性。

In other words, could different go routine grab the same elem in the channel, or while one go routine is reading the buffer, the other go routines already read and processed some of the elements? 换句话说,不同的go例程可以在通道中捕获相同的元素,还是当一个go例程正在读取缓冲区时,另一个go例程已经读取并处理了某些元素?

Nope... 不...

I believe a misunderstanding is in difference between non-blocking and thread safe concepts. 我相信非阻塞和线程安全概念之间的区别是一种误解。

Non blocking (buffered) channels 非阻塞(缓冲)通道

Sends to a buffered channel block only when the buffer is full. 仅在缓冲区已满时发送到缓冲的通道块。

Buffered channels just like it said have buffers to store some amount of items. 缓冲通道 就像它所说的那样, 具有用于存储一些项目的缓冲区。 It allows reading goroutine to read without await for writing goroutine put an item to a channel on condition something already written to a channel. 它允许读取goroutine在不等待写入的情况下进行读取goroutine在已将某些内容写入通道的情况下将项目放入通道。 If a channel unbuffered it can contain just single item therefore it requires to block channel for writing before a written item be withdrawn. 如果通道没有缓冲,则只能包含单个项目,因此在撤回已写入的项目之前,它需要阻塞用于写入的通道。 "Blocking/non-blocking" concept doesn't related to "thread safe" concept and non-blocking doesn't mean not thread safe. “阻塞/非阻塞”概念与“线程安全”概念无关,非阻塞并不意味着不是线程安全的。

Thread safety of Go channels Go通道的线程安全

Go channels are thread safe in all available ways of use. Go通道在所有可用的使用方式中都是线程安全的。 Channel is a reference type so once allocated with make channel could be passed by value because it has implicit pointer to a single memory slot. 通道是一种引用类型,因此一旦分配了make通道,就可以按值传递,因为它具有指向单个内存插槽的隐式指针。 Obviously contained in a channel item never be copied and couldn't be read twice. 显然,频道项目中包含的内容永远不会被复制,并且无法被读取两次。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM