有没有可靠的方法来确保Go通道不会在读取时阻止?

时间:2015-04-29 00:36:26

标签: multithreading concurrency go

这是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工具中的类似工具相比......)

2 个答案:

答案 0 :(得分:9)

这正是select中的默认案例:

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

如果可以,则指定elm,否则返回零值。有关更为广泛的示例,请参阅Effective Go中的“泄漏缓冲区”。

答案 1 :(得分:2)

Rob Napier的回答是正确的。

但是,假设它是一种反模式,你可能很难实现非阻塞行为。

使用Go,您必须担心阻止。来吧,阻止没有内疚。它可以使代码更容易编写,尤其是在处理i / o时。

CSP允许您设计数据驱动的并发程序,这些程序可以很好地扩展(因为没有使用过多的互斥量)。通过通道进行通信的一小组goroutine可以表现得像一个更大系统的组件;这些组件(也通过通道进行通信)可以分组为更大的组件;这种模式在不断增加的规模上重复。

传统上,人们从顺序代码开始,然后尝试通过添加goroutines,channel,mutex等来添加并发性。作为练习,尝试不同的东西:尝试将系统设计为最大并发 - 使用尽可能深入的goroutines和渠道。您可能对您实现的性能不感兴趣...因此可能会尝试考虑如何通过组合(而不是划分)块来改进它,从而减少总数goroutines,从而实现更优化的并发性。