Not seeing the expected side effects from goroutines

Issue

I’m trying to get a grasp on goroutines. Take this code:

package main
import "fmt"

var (
    b1 []float64
    b2 []float64
)

func main() {
    go fill(&b1, 10)
    go fill(&b2, 10)

    fmt.Println(b1,b2)

    var s string
    fmt.Scanln(&s)
}

func fill(a *[]float64, n int) {
    for i:=0; i<n; i++ {
        *a = append(*a, rand.Float64()*100)
    }
}

As you see, I’m trying to fill two slices. But when run this way (with go fill()), it prints two empty slices. Why is this not working?

Solution

Any goroutines you start aren’t guaranteed to have finished (or even started!) until you’ve explicitly waited on them using a sync.WaitGroup, channel, or other mechanism. This works:

package main

import (
    "fmt"
    "math/rand"
    "sync"
)

var (
    b1 []float64
    b2 []float64
)

func main() {
    wg := new(sync.WaitGroup)
    wg.Add(2)
    go fill(&b1, 10, wg)
    go fill(&b2, 10, wg)
    wg.Wait()

    fmt.Println(b1)
    fmt.Println(b2)
}

func fill(a *[]float64, n int, wg *sync.WaitGroup) {
    for i := 0; i < n; i++ {
        *a = append(*a, rand.Float64()*100)
    }
    wg.Done()
}

(Just speaking of style, if it were me I’d make this function return the enlarged slice so it’s similar to append() itself, and Go’s Code Review Comments suggest passing values, though it’s not at all unconventional to extend a slice passed as a pointer receiver (“this”) parameter.)

Answered By – twotwotwo

Answer Checked By – Gilberto Lyons (GoLangFix Admin)

Leave a Reply

Your email address will not be published.