0

i am new to the Go language, and looking for some help for the concurrency model. say I want to make 2 http calls concurrently, and wait for both of them to finish then process/merge the response data. here is the code i have

func main() {
    var wg sync.WaitGroup
    wg.Add(2)
    c1 := make(chan string)
    c2 := make(chan string)
    go foo(c1, &wg)
    go bar(c2, &wg)
    wg.Wait()
    foo := <-c1
    bar := <-c2
    fmt.Println("foo: ", foo)
    fmt.Println("bar: ", bar)
}

func foo(c chan string, wg *sync.WaitGroup) {
    defer wg.Done()
    c <- "foo"
}

func bar(c chan string, wg *sync.WaitGroup) {
    defer wg.Done()
    c <- "bar"
}

however when i run it, it gives the error fatal error: all goroutines are asleep - deadlock!

I can get it working without the WaitGroup, but just curious why this gets to the deadlock, and whats the best way of doing it

3 Answers 3

2

The goroutines will block waiting to write to the channel, because the channel read happens after goroutines end (after wg.Done), thus the deadlock.

Simples solution here is to get rid of the waitgroup. The channel read operations will block until the goroutines write to the channel, so after both channels are read, there is no need to wait.

Sign up to request clarification or add additional context in comments.

Comments

1

Indeed the waitgroup is not really needed here. But if you want to continue experimenting with goroutines and channels, then you can also try and make the channels buffered, like:

c1 := make(chan string, 1)
c2 := make(chan string, 1)

What happens then is that you can write a single entry to each channel without blocking.

Comments

0

Reading/writing to an unbuffered channel is a blocking call, meaning that these lines:

c <- "foo"
c <- "bar"

will hang until you reach calls that pull the values from the channels, i.e., these lines:

foo := <-c1
bar := <-c2

The cause of your deadlock is calling wg.Wait() before these two lines. In order to move past wg.Wait(), all waitgroups must complete, but your waitgroups cannot because wg.Done() is deferred until c <- "foo"/c <- "bar" unblock. As mentioned before, these cannot unblock until you reach foo := <-c1/bar := <-c2, and these cannot be reached because of wg.Wait(). You see the how no progress is possible, hence the deadlock.

The best practice is to avoid using waitgroups and mutex until absolutely necessary. Often, (like in this case) a solution is possible in pure Go and these packages only complicate the code.

1 Comment

this is a little too bold that i upvote for your answer The best practice is to avoid using waitgroups and mutex until absolutely necessary. Often, (like in this case) a solution is possible in pure Go and these packages only complicate the code. mutex is part of the stdlib.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.