Goroutines: Where to close

Issue

I am struggling to understand where I should close my channels.

This bit of code takes about 0.7 seconds:

options := [3]string{"0", "1", "2"}
str := fmt.Sprintf("%6d ", id)
for j := 0; j < 40000; j++ {
    str += options[rand.Intn(3)]
}
str += "\n"

Adding an io.Writestring does not make a difference to the time, so the problem is this bit.

I want roughly 100,000 records like these so I thought to put in a goroutine.

func main() {
    file, _ := os.Create("myfile.txt")
    ch := make(chan string)
    for i := 0; i < 100000; i++ {
       go generate(i, ch)
    }

    counter := 0
    for result := range ch {
       counter++
       io.WriteString(file, result)
       if counter == 100000 {
           close(ch)
       }
    }
    file.Close()
}

func generate(id int, c chan string) {
    options := [3]string{"0", "1", "2"}
    str := fmt.Sprintf("%6d ", id)
    for j := 0; j < 40000; j++ {
        str += options[rand.Intn(3)]
    }
    str += "\n"
    c <- str
}

From what I understand is that I am closing the channel on the receiver side, which is not ideal? Also, this way all 100,000 should be sent to goroutines first, before I can receive any. Can I send requests to generate a record and start receiving at the same time?

Solution

Using a counter to close your channel is not a good practise.You can make use of sync.WaitGroup. This allows you to have a better control on when to close your channel:

func main() {

    var wg sync.WaitGroup

    ch := make(chan string)
    file, _ := os.Create("myfile.txt")

    for i := 0; i < 100000; i++ {
        wg.Add(1)

        go func(i int) {
            defer wg.Done()

            options := [3]string{"0", "1", "2"}
            str := fmt.Sprintf("%6d ", i)
            for j := 0; j < 40000; j++ {
                str += options[rand.Intn(3)]
            }
            str += "\n"
            ch <- str
        }(i)
    }

    go func() {
        wg.Wait()
        close(ch)
    }()

    for result := range ch {
        io.WriteString(file, result)
    }
    file.Close()
}

Answered By – Ashwin Shirva

Answer Checked By – Mary Flores (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.