How to execute multiple goroutines in parallel without a Deadlock - go

So I have been trying to run mutliple goroutines in parallel using a WaitGroup. Whatever I try I always end up with a "fatal error: all goroutines are asleep - deadlock!"
This is what my code looks like right now:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
ch := make(chan time.Duration)
var wg sync.WaitGroup
for _, v := range []time.Duration{5, 1} {
wg.Add(1)
go func() {
defer wg.Done()
wait(v, ch)
}()
}
wg.Wait()
}
func wait(seconds time.Duration, c chan time.Duration) {
time.Sleep(seconds * time.Second)
c <- seconds
}
However this results in a deadlock and I can't figure out why.
I have been trying to read the values after the WaitGroup with the following code:
close(ch)
for v := range ch {
fmt.Println(v)
}
However it seems it wouldn't even reach this part.
Thank you!

There are two problems withe the code:
You must close the channel only after all go-routines have finished
The value of v is being lost during the iteration
In go, the for loop will reuse v, so all go-routines will have the same value on the wait call.
package main
import (
"fmt"
"sync"
"time"
)
func main() {
ch := make(chan time.Duration)
var wg sync.WaitGroup
for _, v := range []time.Duration{5, 1} {
wg.Add(1)
v := v // <- this
go func() {
defer wg.Done()
wait(v, ch)
}()
}
go func() { // Close the channel only after go-routines finish
wg.Wait()
close(ch)
}()
for v := range ch { // Will loop until channel is closed
fmt.Println(v)
}
}
func wait(seconds time.Duration, c chan time.Duration) {
time.Sleep(seconds * time.Second)
c <- seconds
}

You need to close the worker channel after all the workers are done. You are closing it immediately from the main goroutine.
So do this:
go func() {
wg.Wait()
close(ch)
}()
Also your wait function already takes a time.Duration so really it should be in the real time at that point & not multiplied by time.Second. if you want to pass in units of seconds, consider changing the input type to int to avoid confusion.

Related

WaitGroup - fatal error: all goroutines are asleep - deadlock

Can someone explain why this code throws an "fatal error: all goroutines are asleep - deadlock!"?
I can't seem to find what is wrong. I've seen some questions about this specific error, but the reason was mostly looping through a channel without closing it.
Thank you!
package main
import (
"fmt"
"sync"
"time"
)
func main() {
ch := make(chan time.Duration)
var wg sync.WaitGroup
for _, v := range []time.Duration{5, 1} {
wg.Add(1)
go wait(v, ch, wg)
fmt.Println(<-ch)
}
wg.Wait()
}
func wait(seconds time.Duration, c chan time.Duration, wg sync.WaitGroup) {
defer wg.Done()
time.Sleep(seconds * time.Second)
c <- seconds
}
You have to pass the WaitGroup by reference, not by value. Otherwise the Done has no effect. The documentation of this type says:
A WaitGroup must not be copied after first use.
Fix your code to this and it will work:
func main() {
ch := make(chan time.Duration)
var wg sync.WaitGroup
for _, v := range []time.Duration{5, 1} {
wg.Add(1)
go wait(v, ch, &wg)
fmt.Println(<-ch)
}
wg.Wait()
}
func wait(seconds time.Duration, c chan time.Duration, wg *sync.WaitGroup) {
defer wg.Done()
time.Sleep(seconds * time.Second)
c <- seconds
}
It is also common to express this pattern as follows:
func main() {
ch := make(chan time.Duration)
var wg sync.WaitGroup
for _, v := range []time.Duration{5, 1} {
wg.Add(1)
go func() {
defer wg.Done()
wait(v, ch)
}()
fmt.Println(<-ch)
}
wg.Wait()
}
func wait(seconds time.Duration, c chan time.Duration) {
time.Sleep(seconds * time.Second)
c <- seconds
}
What's nice about this case is that wait doesn't have to be aware of any wait groups (it could be a 3rd-party function, for example), and there's no confusion about passing a wait group by value or reference.

How to fix the deadlock in this code, and extend it so that it can wait on a channel which has no writers?

I'm trying to learn channels in Go, so this is a contrived example of having a channel where there are multiple writers, but only one reader. This is a very basic example, but I would like to take it further, by imagining its a http server, where there is a goroutine created for each new request, and each goroutine makes a write on a channel.
func Start2(){
var wg sync.WaitGroup
wg.Add(2)
c := make(chan int)
go func(){
defer wg.Done()
i := 0
for {
i+=2
c<-i
time.Sleep(time.Duration(rand.Intn(5)) * time.Second)
if i > 10 {
break
}
}
}()
go func(){
defer wg.Done()
i := 1
for {
i+=2
c<-i
time.Sleep(time.Duration(rand.Intn(5)) * time.Second)
if i > 10 {
break
}
}
}()
for a := range c {
log.Println(a)
}
wg.Wait()
}
Why does this deadlock?
How could I organise the logic of reading from the channel, so that the code doesn't deadlock when there are no writers on the channel? (For instance, in the end goal example, if there isn't currently a request being made to the http server)?
Unbuffered channel needs at least two goroutines to operate and by exiting one of then. the Go runtime is smart enough to detect the deadlock, so you have two options here:
Since you want to use the channel in the http server - there is no deadlock here:
package main
import (
"fmt"
"log"
"net/http"
"time"
)
func main() {
http.HandleFunc("/", home)
go func() {
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal(err)
}
}()
count := 0
for a := range c {
count++
fmt.Println(count, a)
}
}
var c = make(chan time.Time)
func home(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hi")
c <- time.Now()
}
Or close the channel to force the main goroutine to exit too - just for your current example code - try it:
package main
import (
"log"
"math/rand"
"sync"
"time"
)
func main() {
wg := &sync.WaitGroup{}
wg.Add(2)
c := make(chan int)
go routine(0, c, wg)
go routine(1, c, wg)
go func() {
wg.Wait()
close(c)
}()
for a := range c {
log.Println(a)
}
}
func routine(i int, c chan int, wg *sync.WaitGroup) {
defer wg.Done()
for {
i += 2
c <- i
time.Sleep(time.Duration(rand.Intn(5)) * time.Second)
if i > 10 {
break
}
}
}
You are not closing your channel, you need to close it when you are done.
You can create a goroutine for reading from your channel and close it after the wait group.
Example:
var wg sync.WaitGroup
wg.Add(2)
c := make(chan int)
go func() {
defer wg.Done()
i := 0
for {
i += 2
c <- i
time.Sleep(time.Duration(rand.Intn(5)) * time.Second)
if i > 10 {
return
}
}
}()
go func() {
defer wg.Done()
i := 1
for {
i += 2
c <- i
time.Sleep(time.Duration(rand.Intn(5)) * time.Second)
if i > 10 {
break
}
}
}()
//read channel in a goroutine
go func() {
for a := range c {
log.Println(a)
}
}()
wg.Wait()
//close channel when done
close(c)

Wait for concurrent workers to finish before exiting

The following code has an obvious problem: the program will exit before all the work is finished by the workers.
Goroutines of the workers are launched before the sender starts sending data, which must remain. Starting these goroutines from the sender function is not an option. It would be easy to do so, however, need to learn a more complex synchronization technique.
What would be the correct way to wait for the workers to finish?
Have tried closing the worker1CH and worker2CH channels, as well as adding dedicated sync.WaitGroups to each worker.
package main
import (
"log"
"math/rand"
"sync"
)
func main() {
worker1CH := make(chan int, 1)
worker2CH := make(chan int, 1)
// worker for even numbers
go func(in chan int) {
for i := range in {
log.Print(i)
}
}(worker1CH)
// worker for odd numbers
go func(in chan int) {
for i := range in {
log.Print(i)
}
}(worker2CH)
// sender which sends even numbers to worker1CH, and odd numbers to worker2CH
var wg sync.WaitGroup
wg.Add(1)
go func(wg *sync.WaitGroup, evenChan chan int, oddChan chan int) {
defer wg.Done()
data := rand.Perm(10)
for _, i := range data {
switch i%2 {
case 0:
evenChan <- i
default:
oddChan <- i
}
}
}(&wg, worker1CH, worker2CH)
wg.Wait()
}
Wait for the two receiving goroutines to complete using a wait group. Use one wait group to wait for both goroutines.
Close the channels after sending all values so that the loops in the receiving goroutines exit.
There's no need to wait for the sending goroutine. The grouting competes all of it's work before the other coroutines complete.
worker1CH := make(chan int, 1)
worker2CH := make(chan int, 1)
var wg sync.WaitGroup
wg.Add(2) // <-- wait for the two receiving goroutines.
// worker for even numbers
go func(wg *sync.WaitGroup, in chan int) {
defer wg.Done() // <--- add this line
for i := range in {
log.Print(i)
}
}(&wg, worker1CH)
// worker for odd numbers
go func(wg *sync.WaitGroup, in chan int) {
defer wg.Done() <-- add this line
for i := range in {
log.Print(i)
}
}(&wg, worker2CH)
// sender which sends even numbers to worker1CH, and odd numbers to worker2CH
go func(evenChan chan int, oddChan chan int) {
defer close(evenChan) // <-- close channel so that receiver exits loop
defer close(oddChan) // <-- ditto
data := rand.Perm(10)
for _, i := range data {
switch i % 2 {
case 0:
evenChan <- i
default:
oddChan <- i
}
}
}(worker1CH, worker2CH)
wg.Wait()
Run the example on the Go Playground.
Have Been able to create worker1Done and worker2Done channels, then waiting for the work to finish.
Also had to add close(evenChan) and close(oddChan) to the sender function to avoid the fatal error: all goroutines are asleep - deadlock! error
package main
import (
"log"
"math/rand"
"sync"
)
func main() {
worker1CH := make(chan int, 1)
worker2CH := make(chan int, 1)
worker1Done := make(chan bool)
worker2Done := make(chan bool)
// worker for even numbers
go func(in chan int, done chan bool) {
for i := range in {
log.Print(i)
}
done <- true
}(worker1CH, worker1Done)
// worker for odd numbers
go func(in chan int, done chan bool) {
for i := range in {
log.Print(i)
}
done <- true
}(worker2CH, worker2Done)
// sender which sends even numbers to worker1CH, and odd numbers to worker2CH
var wg sync.WaitGroup
wg.Add(1)
go func(wg *sync.WaitGroup, evenChan chan int, oddChan chan int) {
defer wg.Done()
data := rand.Perm(10)
for _, i := range data {
switch i%2 {
case 0:
evenChan <- i
default:
oddChan <- i
}
}
close(evenChan)
close(oddChan)
}(&wg, worker1CH, worker2CH)
wg.Wait()
<- worker1Done
<- worker2Done
}
Since your sender has fix size so it will be exiton its own and you can just close the channel for reader and wait
package main
import (
"log"
"math/rand"
"sync"
)
func reader(in chan int, wg *sync.WaitGroup) {
defer wg.Done()
for i := range in {
log.Print(i)
}
}
func main() {
var wg sync.WaitGroup
worker1CH := make(chan int, 1)
worker2CH := make(chan int, 1)
wg.Add(1)
// worker for even numbers
go reader(worker1CH, &wg)
wg.Add(1)
// worker for odd numbers
go reader(worker2CH, &wg)
// sender which sends even numbers to worker1CH, and odd numbers to worker2CH
sender(worker1CH, worker2CH)
close(worker2CH)
close(worker1CH)
wg.Wait()
}
func sender(evenChan chan int, oddChan chan int) {
data := rand.Perm(10)
for _, i := range data {
switch i % 2 {
case 0:
evenChan <- i
default:
oddChan <- i
}
}
}
playground link https://play.golang.org/p/JJ9ngCHUvbS

Go: transformed channel

Let's say I have an int channel in Go:
theint := make(chan int)
I want to wrap this channel in a new channel called incremented
incremented := make(chan int)
Such that:
go func() { theint <- 1 }
<- incremented // 2
appended can be assumed to be the only one that reads from the int.
It will work if a run a goroutine in the background
go func() {
for num := range theint {
incremented <- num + 1
}
}
However, I prefer to do it without a goroutine since I can't control it in my context.
Is there a simpler way to do it?
One thing that came to mind is python's yield:
for num in theint:
yield num + 1
Is something like this possible in go?
Generator pattern
What you are trying to implement is generator pattern. To use channels and goroutines for implementation of this pattern is totally common practice.
However, I prefer to do it without a goroutine since I can't control it in my context.
I believe the problem is deadlock
fatal error: all goroutines are asleep - deadlock!
To avoid deadlocks and orphaned (not closed) channels use sync.WaitGroup. This is an idiomatic way to control goroutines.
Playground
package main
import (
"fmt"
"sync"
)
func incGenerator(n []int) chan int {
ch := make(chan int)
var wg sync.WaitGroup
wg.Add(len(n))
for _, i := range n {
incremented := i + 1
go func() {
wg.Done()
ch <- incremented
}()
}
go func() {
wg.Wait()
close(ch)
}()
return ch
}
func main() {
n := []int{1, 2, 3, 4, 5}
for x := range incGenerator(n) {
fmt.Println(x)
}
}
One thing you can also consider is having a select on the int channel and an exit channel - in an infinite for loop. You can choose a variable increment value too. Please see code below:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var accum int //accumulator of incremented values
var wg sync.WaitGroup
c1 := make(chan int)
exChan := make(chan bool)
wg.Add(1)
go func() {
time.Sleep(time.Second * 1)
c1 <- 1
wg.Done()
}()
wg.Add(1)
go func() {
time.Sleep(time.Second * 2)
c1 <- 2
wg.Done()
}()
wg.Add(1)
go func() {
time.Sleep(time.Second * 2)
c1 <- 5
wg.Done()
}()
go func() {
wg.Wait()
close(exChan)
}()
for {
var done bool
select {
case incBy := <-c1: //Increment by value in channel
accum += incBy
fmt.Println("Received value to increment:", incBy, "; Accumulated value is", accum)
case d := <-exChan:
done = !(d)
}
if done == true {
break
}
}
fmt.Println("Final accumulated value is", accum)
}
Playground: https://play.golang.org/p/HmdRmMCN7U
Exit channel not needed, if we are having non-zero increments always. I like #I159 's approach too!
Anyways, hope this helps.

Golang - signal other goroutines to stop and return when one goroutine has found the result

I would like to speed up a certain task in Go by starting several worker goroutines.
In the example below, I'm looking for a "treasure". Worker goroutines that are started will dig forever for items until they are told to stop. If the item is a wanted treasure, then it is placed onto a shared buffered channel with a capacity equals to the number of workers.
The program is only interested in getting one treasure. It also has to make sure that all workers goroutines will return and not be blocked forever.
The example works, but is there a cleaner or more idiomatic way to ensuring the above?
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
var wg sync.WaitGroup
func digTreasure() int {
time.Sleep(5 * time.Millisecond)
return rand.Intn(1000)
}
func worker(i int, ch chan int, quit chan struct{}) {
defer func() {
fmt.Println("worker", i, "left")
wg.Done()
}()
for {
treasure := digTreasure()
if treasure%100 == 0 {
fmt.Println("worker", i, "found treasure", treasure)
ch <- treasure
return
}
select {
case <-quit:
fmt.Println("worker", i, "quitting")
return
default:
}
}
}
func main() {
rand.Seed(time.Now().UnixNano())
n := 10
ch, quit := make(chan int, n), make(chan struct{})
fmt.Println("Searching...")
wg.Add(n)
for i := 0; i < n; i++ {
go worker(i, ch, quit)
}
fmt.Println("I found treasure:", <-ch)
close(quit)
wg.Wait()
fmt.Println("All workers left")
}

Resources