How does make (chan bool) behave differently than make (chan bool, 1)?

My question arises from trying to read a channel, if possible, or write it, if possible, using the select statement.

I know that the channels specified as make(chan bool, 1) are buffered, and part of my question is what is the difference between them and make(chan bool) - which this page says is the same as make(chan bool, 0) --- What is the channel point that can hold 0 values ​​in it?

See 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") } } 

Exit:

 Neither Neither Neither Neither Neither 

(Removing the default case results in a deadlock!)

Now look at 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 output:

 Write Read Write Read Write 

In my case, pin B is what I want. What are the benefits of unbuffered channels? All the examples that I see on golang.org seem to use them to send one signal / value at a time (and that’s all I need), but, like in Playground A, the channel is never read or written . What am I missing in my understanding of channels?

+8
go channel
source share
3 answers

what is the point of the channel that can hold 0 values ​​in it

First, I want to point out that the second parameter here means the size of the buffer, so this is just a channel without buffers (unbuffered channel).

Actually, the reason your problem arises. Unbuffered channels are write-only when someone blocks their reading, which means that you must have some coroutines to work - instead of one.

Also see Go memory model :

And receiving from an unbuffered channel occurs before sending is completed on this channel.

+9
source share

An unbuffered channel means that reading and writing from and to the channel is blocked.

In the select statement:

  • reading will work if any other goroutine was currently blocked in a letter to the channel
  • write will work if any other goroutine is currently locked while reading to the channel
  • otherwise, the default event is default , which happens in your case A.
+3
source share

Unbuffered channels (created without capacity) block the sender until someone can read them, so to make it work as you expect, you must use two goroutines to avoid a dead end in the same stream.

For example, using this code: http://play.golang.org/p/KWJ1gbdSqf

It also includes a mechanism for the main func to detect when both goroutines have finished.

 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 } 

It will not show alternative Read and Write, because as soon as send writes to the channel, it is blocked before it can print the "Write", therefore, execution proceeds to recv , which receives the channel and prints of "Read". It will try to read the channel again, but it will be blocked, and execution will move to send . Now send can write the first "Write", send to the channel (without blocking, because now the receiver is ready) and write the second "Write". In any case, this is not deterministic, and the scheduler can move execution at any point to any other executable server (at least in the latest version 1.2).

+3
source share

All Articles