I am trying to print N numbers from 2 go routines:
go routine odd(): this can only print odd numbers
go routine even(): this can only print even numbers
The output should be: 1 2 3 4 5 6 7 8 9 10
I am trying to solve this problem using sync.WaitGroup. I have following queries:
Q1. Which concurrency mechanism best suited for this problem? channel, waitgroup, mutex, etc? It would be ideal if you could provide a working code for the same.
Q2. Why I am not able to print the sequence correctly through below code? I am doing something wrong which I am not able to rectify. please help in rectifying.
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
var wgO sync.WaitGroup
var wgE sync.WaitGroup
func even() {
defer wg.Done()
for i := 2; i <= 10; i += 2 {
wgE.Add(1)
wgO.Wait()
fmt.Println(i)
wgE.Done()
}
}
func odd() {
defer wg.Done()
for i := 1; i <= 10; i += 2 {
wgO.Add(1)
fmt.Println(i)
wgO.Done()
wgE.Wait()
}
}
func main() {
wg.Add(2)
go even()
go odd()
wg.Wait()
}
Q1: Which concurrency mechanism best suited for this problem?
A1: None. Your problem of printing sequential numbers is not a concurrent one. So even if you implemented a solution that uses Go's concurrent mechanisms (either with channels or mutexs), it wouldn't/couldn't actually run concurrently, since what you want is sequentially printing your numbers. Running concurrently would print numbers is a non-deterministic order.
Q2: Why I am not able to print the sequence correctly through below code?
A2: Your code prints out of order because once go routines have been triggered, you have no way of knowing the order in which they are executed. So the code:
...
go even()
go odd()
...
doesn't even guarantee that the loop inside your even
function will start before the loop inside your odd
function, even thou the even
function is called before.
A2.1: Your code can panic sometimes WaitGroup is reused before previous Wait has returned
, because it's possible for wgO.Done()
inside odd
function to be called before wgO.Wait()
is called inside the even
function.
The following is a very silly implementation using sync.WaitGroup
that works, and illustrates how the solution to your problem has to break concurrency to work. In order to print the numbers in order, I have to wait the completion of each go routine...
func main() {
var wg sync.WaitGroup
for i := 0; i <= 10; i++ {
if i%2 == 0 {
wg.Add(1)
go func(i int) {
defer wg.Done()
fmt.Println(i)
}(i)
wg.Wait()
} else {
wg.Add(1)
go func(i int) {
defer wg.Done()
fmt.Println(i)
}(i)
wg.Wait()
}
}
}
I wouldn't get too caught up in this problem as it's not a good example for leaning Go's concurrency mechanism.
There is a great course on cooursera for learning Go's concurrency here