Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang channel output order

Tags:

go

channel

func main() {
  messages := make(chan string)
  go func() { messages <- "hello" }()
  go func() { messages <- "ping" }()
  msg := <-messages
  msg2 := <-messages
  fmt.Println(msg)
  fmt.Println(msg2)

The above code consistently prints "ping" and then "hello" on my terminal. I am confused about the order in which this prints, so I was wondering if I could get some clarification on my thinking.

I understand that unbuffered channels are blocking while waiting for both a sender and a receiver. So in the above case, when these 2 go routines are executed, there isn't, in both cases,a receiver yet. So I am guessing that both routines block until a receiver is available on the channel.

Now... I would assume that first "hello" is tried into the channel, but has to wait... at the same time, "ping" tries, but again has to wait. Then

msg := <- messages

shows up, so I would assume that at that stage, the program will arbitrarily pick one of the waiting goroutines and allow it to send its message over into the channel, since msg is ready to receive.

However, it seems that no matter how many times I run the program, it always is msg that gets assigned "ping" and msg2 that gets assigned "hello", which gives the impression that "ping" always gets priority to send first (to msg). Why is that?

like image 456
hundred_dolla_tea Avatar asked Jun 02 '18 07:06

hundred_dolla_tea


2 Answers

It’s not about order of reading a channel but about order of goroutines execution which is not guaranteed.

Try to ‘Println’ from the function where you are writing to the channel (before and after writing) and I think it should be in same order as reading from the channel.

like image 71
Alexander Trakhimenok Avatar answered Sep 17 '22 15:09

Alexander Trakhimenok


In Golang Spec Channels order is described as:-

Channels act as first-in-first-out queues. For example, if one goroutine sends values on a channel and a second goroutine receives them, the values are received in the order sent.

It will prints which value is available first to be received on other end. If you wants to synchronize them use different channels or add wait Groups.

package main

import (
    "fmt"
)

func main() {
  messages1 := make(chan string)
  messages2 := make(chan string)
  go func(<-chan string) {
        messages2 <- "ping" 
    }(messages2)
  go func(<-chan string) {
        messages1 <- "hello" 
    }(messages1)
  fmt.Println(<-messages1)
  fmt.Println(<-messages2)
}

If you see you can easily receive any value you want according to your choice using different channels.

Go playground

like image 22
Himanshu Avatar answered Sep 17 '22 15:09

Himanshu