Some thoughts on the Golang concurrency and channel

I just tried the Golang recently. It’s easy to pick up if you have some C and OOP background. The only thing I’m not completely clear is the go concurrency.

The relationship between goroutine and threads could be N to 1 where N >= 1. That is to say with only one thread you can run several goroutines concurrently (switching between them in a very short interval which makes you feel like they are executing simultaneously. It’s not parallelism since you only have one thread.)

The goroutines can communicate through channels. A channel call may be blocked and the goroutine making that call will be set to waiting, but the thread running the goroutine WILL NOT BLOCK (unless the goroutine makes a BLOCKING SYSTEM CALL. This will cause the thread to block.) and move on to other runnable goroutines. Later, when the channel block is cleared, the thread will come back to run the previous channel blocked goroutine.

A goroutine can yield back to the thread in the following ways (check this post on stackoverflow):

  • The select statement can yield control back to the thread.
  • sending on a channel can yield control back to the thread.
  • Doing IO operations can yield control back to the thread.
  • runtime.Gosched() explicitly yields control back to the thread.

Let’s look at some examples to illustrate the ideas above (wordpress does not support Golang…).
go1

The output would be:

go1-res

One possible execution order could be (as suggested on stack overflow):

  1. Main function creates two go routines.
  2. The scheduler chooses to switch to the go routine display immediately and print out the message. Then display is in a channel block since the receiver of the channel call is not ready yet.
  3. The scheduler chooses to run the sum goroutine next. It prints out the sum and block on channel call (not sure if I’m right about this part).
  4. The scheduler switches back to main since it is the only one that is not channel blocked. <-c wants to receive data and the sender is also ready (from display). So both side is ready and the execution continues. Well we print out true and ends the program. The data “false” from the sum goroutine never got sent.

If you are expecting only the output from display, you can do the following things:

The program above uses only one thread. You can explicitly set the number of threads to run the program by using runtime.GO.MAXPROCS()

go2

Here we have two threads running two goroutines. One executes display (we call it ThreadA) while the other executes the sum (we call it ThreadB). Since sum takes longer, display reaches the channel call (blocked) first. So ThreadA looks for another routine that is runnable. Ah main is open (sum is still executed by ThreadB). In main, it receives data from channel. Since we have both side ready, main continues execution and exit the program regardless of the status of the sum routine.

go2-res

Another way to do it is to use the time.Sleep() in the sum routine.

go3

Once again we only have one thread. While the thread executes goroutine sum, it finds out the time.Sleep call. This will cause the routine to hang and yield the control back to the Go Scheduler.

  1. Main creates two go routines.
  2. Go scheduler executes display and block on channel call.
  3. Go scheduler executes sum. Sum yields control back to the scheduler because of the time.Sleep call.
  4. Scheduler executes main. Print out the bool value from the channel and exits.

Note that the execution order above is just one possibility. There could be other orders. Another very good post on stack overflow: http://stackoverflow.com/questions/13107958/what-exactly-does-runtime-gosched-do

In the latest version, the execution context can switch on IO functions. So the real execution order for the code above can have more possibilities.