Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to understand the channel communication rules in golang memory model?

Learning golang on the way, I got a little confused when trying to understand the channel communications described in the memory model spec as below:

  1. A send on a channel happens before the corresponding receive from that channel completes.
  2. The closing of a channel happens before a receive that returns a zero value because the channel is closed.
  3. A receive from an unbuffered channel happens before the send on that channel completes.
  4. The kth receive on a channel with capacity C happens before the k+Cth send from that channel completes.

The first 2 rules are clear and easy to understand, while I really got confused about the 3rd rule, which seems opposite to others... Did I miss anything special about unbuffered channel? Or am I correct If I take it like the below with the example in the spec:

var c = make(chan int)
var a string

func f() {
    a = "hello, world"
    <-c    // A
}
func main() {
    go f()
    c <- 0 // B
    print(a)
}

For an unbuffered channel, the send operation(B) is blocked until the receiver gets ready to receive the value(A)? (like: B starts and does not return until A executes) Is it accurate?

And I find the following statements in Effective Go spec, but there's still discrepancy from my understanding... So can someone please explain this in a simple and straightforward way?

Receivers always block until there is data to receive. If the channel is unbuffered, the sender blocks until the receiver has received the value. If the channel has a buffer, the sender blocks only until the value has been copied to the buffer; if the buffer is full, this means waiting until some receiver has retrieved a value.

like image 550
Roy Ling Avatar asked Oct 19 '17 04:10

Roy Ling


People also ask

How does channels work in Golang?

In Golang, or Go, channels are a means through which different goroutines communicate. Think of them as pipes through which you can connect with different concurrent goroutines. The communication is bidirectional by default, meaning that you can send and receive values from the same channel.

What are buffered and unbuffered channels in Golang?

By default channels are unbuffered, which states that they will only accept sends (chan <-) if there is a corresponding receive (<- chan) which are ready to receive the sent value. Buffered channels allows to accept a limited number of values without a corresponding receiver for those values.

What's the default buffer size of the channel in Go?

By default, a channel buffer size is 0 also called as unbuffered channel.

Are Golang channels blocking?

Channel operation (i.e. write or read) are blocking in nature. This means: When we send data into the channel using a GoRoutine, it will be blocked until the data is consumed by another GoRoutine. When we receive data from channel using a GoRoutine, it will be blocked until the data is available in the channel.


2 Answers

The sentence you've highlighted is the simple explanation you are looking for.

If the channel is unbuffered, the sender blocks until the receiver has received the value.

It's another way of saying point 3:

A receive from an unbuffered channel happens before the send on that channel completes.

When you send on an unbuffered channel, the sender blocks until the receiver has taken the value. This means the receive happens before the send completes.

A buffered channel is different, because the value has somewhere to go. If you're still confused, an example might help:

Say I want to leave a package at your house:

  • If the channel is buffered, you have somewhere for me to leave the package - perhaps a mailbox. This means I can complete my task of giving you the package (sending on the channel) before you receive it (when you check your mailbox).
  • If the channel is not buffered, I have to wait by your front door until you come and take the package off me. You receive the package before I am done with my task of delivering it to you.

For an unbuffered channel, the send operation(B) is blocked until the receiver gets ready to receive the value(A)? (like: B starts and does not return until A executes) Is it accurate?

Yes. This is correct.

like image 67
Timothy Jones Avatar answered Oct 18 '22 20:10

Timothy Jones


For an unbuffered channel, the send operation(B) is blocked until the receiver gets ready to receive the value(A)? (like: B starts and does not return until A executes) Is it accurate?

Yes, this is accurate. Like the documentation says if a channel is unbuffered then sender will block until the value has been received. If the value is never received you will get a deadlock and the program will time out, like in this example:

var c = make(chan int)

func main() {
    c <- 0
    println("Will not print")
}

So an unbuffered channel will block at the send operation until the receiver is ready to receive the value, even if that takes a while. With a buffered channel however the blocking will take place at the receive operation. This example shows how the unbuffered channel waits for the value to be received, but the buffered does not:

package main

import "time"

var c chan int
var a string

func f() {
    time.Sleep(3)
    a = "hello, world"
    <-c // A
}
func test() {
    a = "goodbye"
    go f()
    c <- 0 // B
    println(a)
}

func main() {
    // Unbuffered
    c = make(chan int)
    test()

    // Buffered
    c = make(chan int, 1)
    test()
}

Outputs:

hello, world
goodbye
like image 42
Jack Avatar answered Oct 18 '22 21:10

Jack