make(chan bool)与make(chan bool,1)的行为有何不同?

时间:2013-11-18 06:23:39

标签: go channel

我的问题来自尝试阅读频道,如果可以的话,或者如果可以的话,使用select声明来编写频道。

我知道像make(chan bool, 1)那样指定的频道是缓冲的,我的问题的一部分是它与make(chan bool)之间的区别 - this page所说的是同一个问题make(chan bool, 0) ---一个可以在其中包含0个值的通道的重点是什么?

请参阅 playground A

chanFoo := make(chan bool)

for i := 0; i < 5; i++ {
    select {
    case <-chanFoo:
        fmt.Println("Read")
    case chanFoo <- true:
        fmt.Println("Write")
    default:
        fmt.Println("Neither")
    }
}

输出:

Neither
Neither
Neither
Neither
Neither

(删除default案例导致死锁!!)

现在看 playground B

chanFoo := make(chan bool, 1)   // the only difference is the buffer size of 1

for i := 0; i < 5; i++ {
    select {
    case <-chanFoo:
        fmt.Println("Read")
    case chanFoo <- true:
        fmt.Println("Write")
    default:
        fmt.Println("Neither")
    }
}

B输出:

Write
Read
Write
Read
Write

就我而言, B输出就是我想要的。有什么好的无缓冲通道?我在golang.org上看到的所有示例似乎都使用它们一次发送一个信号/值(这就是我需要的) - 但是在游乐场A中,通道永远不会被读取书面。在理解频道时,我在这里错过了什么?

3 个答案:

答案 0 :(得分:10)

  

可以在其中容纳0个值的通道的重点是什么

首先我要指出这里的第二个参数意味着缓冲区大小,因此它只是一个没有缓冲区的通道(非缓冲通道)。

实际上,这就是您生成问题的原因。未缓冲的通道只有在有人阻止从中读取时才可写,这意味着你应该使用一些协同程序 - 而不是这一个。

另见The Go Memory Model

  

来自无缓冲通道的接收在该通道上的发送完成之前发生。

答案 1 :(得分:4)

无缓冲通道(无容量创建)将阻止发送方,直到有人可以从中读取它们,因此为了使其按预期工作,您应该使用两个goroutine来避免同一线程中的死锁。

例如,使用此代码:http://play.golang.org/p/KWJ1gbdSqf

它还包括一个主函数检测两个goroutine何时完成的机制。

package main

import "fmt"

func send(out, finish chan bool) {
    for i := 0; i < 5; i++ {
        out <- true
        fmt.Println("Write")
    }
    finish <- true
    close(out)
}

func recv(in, finish chan bool) {

    for _ = range in {
        fmt.Println("Read")
    }
    finish <- true

}

func main() {
    chanFoo := make(chan bool)
    chanfinish := make(chan bool)

    go send(chanFoo, chanfinish)
    go recv(chanFoo, chanfinish)

    <-chanfinish
    <-chanfinish
}

它不会显示备用读取和写入,因为只要send写入通道,它就会被阻止,然后才能打印“写入”,因此执行将移至{{1}接收频道并打印“阅读”。它将尝试再次读取该频道,但它将被阻止,执行将移至recv。现在send可以写第一个“写”,发送到通道(没有阻塞,因为现在有一个接收器就绪)并写第二个“写”。在任何情况下,这都不是确定性的,并且调度程序可以在任何时候将执行移动到任何其他正在运行的goroutine(至少在最新的1.2版本中)。

答案 2 :(得分:3)

无缓冲通道意味着对通道的读写操作正在阻塞。

select声明中:

  • 如果其他goroutine当前被阻止写入频道
  • ,则读取将起作用
  • 如果其他goroutine当前被阻止阅读频道
  • ,则写入将有效
  • 否则会执行default个案,这种情况会发生在您的案例A中。