我有一个缓冲的通道,由多个(本例中为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例程可以在通道中抓取相同的元素,或者当一个例程正在读取缓冲区时,另一个例程已经读取并处理了一些元素吗?如何在常规阅读的同时阻止其他常规程序阅读?
答案 0 :(得分:5)
简单回答:不。放置在Go通道上的元素只能读取一次,无论有多少goroutine同时尝试读取通道,无论通道是否被缓冲,这都适用。两个不同的goroutine都不可能读取一个元素,除非该元素多次发送到通道。就通道语义而言,缓冲唯一能做的就是消除了读写同步发生的必要性。
答案 1 :(得分:1)
换句话说,不同的go例程可以在通道中抓取相同的元素,或者当一个例程正在读取缓冲区时,另一个例程已经读取并处理了一些元素吗?
...都能跟得上
我认为误解是非阻塞和线程安全概念之间的区别。
仅在缓冲区已满时才发送到缓冲的通道块。
缓冲通道就像它说有缓冲区来存储一些项目。它允许读取goroutine进行读取而无需等待写入goroutine将项目放入通道,条件已经写入通道。如果一个未缓冲的通道它只能包含单个项目,那么它需要在撤回写入的项目之前阻止写入通道。 “阻塞/非阻塞”概念与“线程安全”概念无关,非阻塞并不意味着线程安全。
Go渠道在所有可用的使用方式中都是线程安全的。 Channel是一种引用类型,因此一旦分配了make
通道,就可以通过值传递,因为它具有指向单个内存槽的隐式指针。显然包含在频道项中永远不会被复制,并且无法读取两次。