Search code examples
gogoroutine

How goroutines are scheduled


I have some basic questions about the way goroutines work.

Code in consideration:

package main

import (
    "fmt"
    "time"
)

type Country struct {
    Name       string
    Continent  string
    Population int32
}

func updatePopulation(c *Country, newBorns int32) {
    c.Population += newBorns
    fmt.Printf("New population of %v is %v\n", c.Name, c.Population)
}

func main() {
    totalStates := 50 // total number of sources, (US states)
    us := Country{"USA", "North America", 32000000}
    for i := 0; i <= totalStates; i++ {
        go updatePopulation(&us, int32(i))
    }
    time.Sleep(time.Second * 5)  // this is just so that we don't need channels
}
  1. We are spawning 50 goroutines here. Does all 50 of them don’t start running unless the main goroutine gets blocked by the sleep? I want to understand in general if the main goroutine must be blocked for the child go routines to get kicked off.

  2. There is nothing in the function updatePopulation that blocks a goroutine. I read about cooperative scheduling and that only when a goroutine is blocked, the other gets executed. But, when I run this, the goroutines are not running in order. Is this because they are scheduled on different threads and these threads are running concurrently on different CPU Cores and not waiting for the other goroutine to complete? My GOMAXPROCS value is 8.

  3. I read that Go runtime creates multiple threads in advance and uses them to schedule the goroutines. Is this per program execution?

Before you say, I know the solution to bring order to this is to use locking but I’m taking this example to understand the basics and not trying to solve the problem with this code.


Solution

    1. There is no guarantee as to when a goroutine starts running, but it won't wait for you to block the main goroutine.
    2. The scheduler is preemptive, which means it can and will put your goroutine to sleep and execute another one even if you don't block. Other goroutines could also be running in parallel, in which case they wouldn't have to wait at all.
    3. All threads are per program execution. The scheduler will not start threads in advance. It starts them on demand, as needed.