【问题标题】:Collision on concurrent read on buffered channel in golang?golang中缓冲通道上的并发读取冲突?
【发布时间】:2017-07-22 19:26:39
【问题描述】:

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

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 例程会在读取时发生冲突吗?换句话说,不同的 goroutine 是否可以在通道中获取相同的元素,或者当一个 goroutine 正在读取缓冲区时,其他 goroutine 已经读取并处理了一些元素?如何在一个 go 例程正在读取时阻止其他 go 例程读取?

【问题讨论】:

  • 在比赛检测器下尝试这个会告诉你更多。请注意,通道的整个想法是在不同的 goroutine 之间提供同步,那么您期望什么?阅读语言规范后,您会期待什么?
  • 规范明确指出它会阻塞非缓冲读取,但对于缓冲通道的读取则不明确。不必显式使用互斥锁来进行一致的读取会很好。
  • 缓冲情况下的规范也很清楚:如果值可用,则读取成功。

标签: go channel goroutine


【解决方案1】:

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

【讨论】:

  • 凯迪斯,谢谢。这个帮助。因此,不可能多次读取单个元素。一个 go 例程试图从缓冲区中读取一个块怎么样,比如说它尝试一次读取 100 个元素,因为它检测到缓冲区的 len() 为 100。在读取块时,另一个 go 例程是否可以读取其中的一些元素那么第一个 go 例程在其块中预期读取的内容将少于 100?
  • 是的,只有单个读取是原子的。如果您想一次读取多个项目而没有交错的可能性,您需要使用互斥锁保护通道,或者通过通道发送对象切片而不是单个对象。
  • 但是请注意,goroutines 很少会检查通道的当前缓冲区长度。由于并发读取或写入,该信息可能会发生变化,您应该循环 range ch,而不是迭代器整数。只需阅读并处理这些项目。如果顺序很重要,请发送有序集合而不是单个项目。
  • 哦,你在 OP 中的嵌套 for 循环可能是一个错误。通道上的范围循环将无限期地继续,直到通道关闭并且所有元素都为空。使用双 for 循环,在通道关闭并清空后,这些 goroutine 中的每一个都将停留在一个无限的空 for 循环中,因为它们会不断重新创建一个范围循环,然后由于通道为空且关闭而立即退出它。
  • 谢谢。根据您的回答和其他阅读,我认为使用“选择”循环读取通道或使用互斥锁的最佳方法。现在一切都好。
【解决方案2】:

换句话说,不同的 goroutine 是否可以在通道中获取相同的元素,或者当一个 goroutine 正在读取缓冲区时,其他 goroutine 已经读取并处理了一些元素?

不...

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

非阻塞(缓冲)通道

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

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

Go 通道的线程安全

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

【讨论】:

    猜你喜欢
    • 2016-08-30
    • 2020-09-03
    • 2019-08-14
    • 2017-11-02
    • 2020-11-11
    • 2019-10-26
    • 2014-09-26
    • 2014-01-30
    • 2018-06-11
    相关资源
    最近更新 更多