【问题标题】:Is there a reliable way to ensure a Go channel does not block on read?是否有可靠的方法来确保 Go 通道不会在读取时阻塞?
【发布时间】:2015-04-29 00:36:26
【问题描述】:

这是a previous thread with a similar name 的后续。

它有一个可接受的答案,但该答案并不能真正回答问题。从那个线程,这里是用例:

if len(myChannel) > 0 {
   // Possible issue here: length could have changed to 0 making this blocking
   elm := <- myChannel
   return elm
 }

OP 将其称为“可能的问题”,但它是一个确定的问题:竞争条件,其中另一个消费者可能在评估 if 条件和执行两个语句之间从通道中提取了一个值。

现在,我们被告知 Go Way 是优先使用通道而不是互斥锁,但在这里,如果不将互斥锁和通道配对在一起,我们似乎甚至无法实现基本的非阻塞读取(通过轮询长度和原子读取),并且使用我们新的并发数据类型而不是通道。

可以吗?真的没有办法通过提前检查空间来可靠地确保recv不会阻塞吗? (与 Java 中的 BlockingQueue.poll() 或其他基于队列的消息传递 IPC 工具中的类似工具比较......)

【问题讨论】:

  • (上一篇文章中接受的答案解决了 OP 的特定用例 - 通过允许竞争条件在特定情况下发生来回避问题。因此,这对他很有用,但并没有真正回答他的问题。我的问题是对他的问题的字面回答。请注意差异并在标记 dup 之前查看我的评论)
  • 从您的问题和链接来看,您似乎正在付出真正的努力,因此可能值得通过 Tour(其中包括 tour.golang.org/concurrency/6 的默认选择)、the spec(部分“ Select statements" 涵盖了这一点),或Effective Go(在标题为“泄漏缓冲区”的部分中的示例中出现了这一点)。
  • 是的,我正在看那些,谢谢。在这几篇文章中,我有点“简化”了我的用例,这样答案是正确的,但没有直接用处。我真正想做的可能被描述为“透明的全有或全无信道复用”,即。只有在所有接收器都可以接收时才发送给任何接收器的扇出。我已经完成了将默认案例的事情(是的,我是 Go 的新手!:p )与 Select 的反射版本相结合所需的东西,并且有一种奇怪的“泵”goroutine 从输入收集并发送到输出...
  • Go Concurrency PatternsConcurrency is not parallelism 会谈中也有很多关于并发的内容。 (这不是对您上一条评论的回应,在我看到它之前就开始写了。)
  • 一个描述您用于检查一组通道的阻塞状态的用例的问题可能会摆脱另一种方法。也许你想要一个 WaitGroup 来等待所有工作人员都准备好,或者也许有一种完全不同的方式来解决整体问题,更容易与 Go 提供的内容相匹配。

标签: multithreading concurrency go


【解决方案1】:

这正是select 中的默认情况:

var elm myType
select {
case elm = <-myChannel:
default:
}
return elm

如果可以,则分配elm,否则返回零值。请参阅Effective Go 中的“泄漏缓冲区”以获得更广泛的示例。

【讨论】:

    【解决方案2】:

    Rob Napier 的回答是正确的。

    但是,假设它是一种反模式,您可能过于努力地实现非阻塞行为。

    使用 Go,您不必担心阻塞。来吧,毫无愧疚地阻止。它可以使代码更容易编写,尤其是在处理 i/o 时。

    CSP 允许您设计可以很好地扩展的数据驱动的并发程序(因为没有过多地使用互斥锁)。通过通道进行通信的小组 goroutine 可以表现得像一个更大系统的组件;这些组件(也通过通道进行通信)可以组合成更大的组件;这种模式以越来越大的比例重复。

    通常,人们从顺序代码开始,然后尝试通过添加 goroutine、通道、互斥锁等来增加并发性。作为练习,尝试一些不同的东西:尝试将系统设计为 最大并发 - 使用尽可能深入地使用 goroutine 和通道。您可能对您所取得的性能不以为然......那么也许可以尝试考虑如何通过组合(而不是划分)块来改善它,减少总数量goroutines 从而实现更优化的并发性。

    【讨论】:

      猜你喜欢
      • 2015-02-25
      • 1970-01-01
      • 2015-01-15
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      • 2011-03-24
      • 2015-12-08
      • 2015-11-07
      相关资源
      最近更新 更多