Concurrent execution but serialized output

Issue

I need to use 3 goroutines named g1, g2, g3. and distribute numbers from 1-10 among the above 3 goroutines in a round-robin fashion. They will do some hypothetical work based on the provided number. And program should print output in the following manner.

g1-1
g2-2
g3-3
g1-4
g2-5
g3-6

Tasks must be performed concurrently but the output must be in sequential order.

I have implemented the below code which distributes numbers and prints but output print order is not guaranteed as mentioned above.

I need some help to fix the below code or suggestions on another approach to get the above-desired output.

Approach 1:

package main

import (
    "fmt"
    "sync"
)

func main() {

    chang1 := make(chan int)
    chang2 := make(chan int)
    chang3 := make(chan int)

    var wg sync.WaitGroup
    wg.Add(3)

    go func() {
        for num := range chang1 {
            fmt.Println("g1", num)
        }
        wg.Done()
    }()

    go func() {
        for num := range chang2 {
            fmt.Println("g2", num)
        }
        wg.Done()

    }()

    go func() {
        for num := range chang3 {
            fmt.Println("g3", num)
        }
        wg.Done()

    }()

    channels := []chan int{chang1, chang2, chang3}

    for i := 1; i <= 10; i++ {

        currentCh := (i - 1) % 3
        channels[currentCh] <- i

    }

    close(chang1)
    close(chang2)
    close(chang3)
    wg.Wait()

}

output (with incorrect sequence)

g1- 1
g1- 4
g2- 2
g3- 3
g1- 7
g2- 5
g2- 8
g3- 6
g3- 9
g1- 10

Solution

if you don’t want to use slice then I think something like this will work:- (playground)

package main

import (
    "fmt"
)

func main() {

    chang1 := make(chan string)
    chang2 := make(chan string)
    chang3 := make(chan string)

    channels := []chan string{chang1, chang2, chang3}

    for i := 1; i < 10; i += 3 {

        go g1(i, channels[i%3])
        go g2(i+1, channels[(i+1)%3])
        go g3(i+2, channels[(i+2)%3])

        fmt.Print(<-channels[i%3])
        fmt.Print(<-channels[(i+1)%3])
        fmt.Print(<-channels[(i+2)%3])
    }

}

func g1(i int, chanel chan string) {

    chanel <- fmt.Sprintln("g1", i)

}

func g2(i int, chanel chan string) {

    chanel <- fmt.Sprintln("g2", i)

}

func g3(i int, chanel chan string) {

    chanel <- fmt.Sprintln("g3", i)

}
output 
g1 1
g2 2
g3 3
g1 4
g2 5
g3 6
g1 7
g2 8
g3 9

but keep in mind in this solution you have to run 3 goroutines then wait for all of them to give the result then go back

if this is not ok for you you need to use bufferd channels.

Answered By – MSH

Answer Checked By – Pedro (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.