How do goroutines work?

Issue

I was following the Go Tour and I am a bit stuck when it comes to goroutines. I understand that they are very lightweight and that every time a goroutine blocks, another one will start but I can’t get my head around how this example actually works:

package main

import (
    "fmt"
    "time"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(1000 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    go say("world")
    say("hello")
}

Playground

I understand that a goroutine is started for the say function with the argument “world”, but as far as I understand that should print “world” five times and “hello” once. However I don’t understand why the output is as it is:

hello
world
hello
world
hello
world
hello
world
hello

From my limited understanding of threads from other languages the output should have been something like this:

hello
world
world
world
world
world

or like this:

world 
world
world
hello
world
world

Why does the second line execute five times as well? Does anything below a go statement classify as part of the go routine?

Also the next slide shows something I can’t get my head round again:

package main

import "fmt"

func sum(a []int, c chan int) {
    sum := 0
    for _, v := range a {
        sum += v
    }
    c <- sum // send sum to c
}

func main() {
    a := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(a[:len(a)/2], c)
    go sum(a[len(a)/2:], c)
    x, y := <-c, <-c // receive from c

    fmt.Println(x, y, x+y)
}

Playground

A goroutine is started for the second half of the slice and then another one for the first part of the slice, however the values x and y have been assigned two different values. The way I see it the sum function will send it’s sum to channel c and then the next sum will send it’s sum to the same channel c so how can the two variables be assigned two different values? Shouldn’t channel c have one single sum value in there?

I appreciate that this is quite a long question but I wasn’t able to find the answer to these questions.

Solution

Why does the second line execute 5 times as well?

The second line will print hello every second 5 times in the main() thread.
But concurrently the first line go say("world") will also print world every seconds five times in a separate goroutine.
The Sleep ensure that each routine yields, allowing the other to resume.

Hence the output:

hello
world
hello
world
hello
world
hello
world
hello

The way I see it the sum function will send it’s sum to channel c and then the next sum will send it’s sum to the same channel c so how can the two variables be assigned two different values?

Because each send will block on c until channel c is read.
Since there are two write to c, you need to read:

 x, y := <-c, <-c // receive from c twice.

The Assignement section of Golang Spec allows for a tuple assignment if:

the number of operands on the left must equal the number of expressions on the right, each of which must be single-valued, and the nth expression on the right is assigned to the nth operand on the left.

Answered By – VonC

Answer Checked By – Jay B. (GoLangFix Admin)

Leave a Reply

Your email address will not be published.