WaitGroups, Buffered Channels, and Deadlocks
I have this bit of code which results in a deadlock and I'm not certain why. I have tried using mutex locking in a few different places, closing channels in and outside of separate go routines, but the result is still the same.
I'm trying to send data through one channel (inputChan), and then read it from another (outputChan)
package main
import (
"fmt"
"sync"
)
func listStuff(wg *sync.WaitGroup, workerID int, inputChan chan int, outputChan chan int) {
defer wg.Done()
for i := range inputChan {
fmt.Println("sending ", i)
outputChan <- i
}
}
func List(workers int) ([]int, error) {
_output := make([]int, 0)
inputChan := make(chan int, 1000)
outputChan := make(chan int, 1000)
var wg sync.WaitGroup
wg.Add(workers)
fmt.Printf("+++ Spinning up %v workers\n", workers)
for i := 0; i < workers; i++ {
go listStuff(&wg, i, inputChan, outputChan)
}
for i := 0; i < 3000; i++ {
inputChan <- i
}
done := make(chan struct{})
go func() {
close(done)
close(inputChan)
close(outputChan)
wg.Wait()
}()
for o := range outputChan {
fmt.Println("reading from channel...")
_output = append(_output, o)
}
<-done
fmt.Printf("+++ output len: %v\n", len(_output))
return _output, nil
}
func main() {
List(5)
}
The code in your main function is sequential and first tries to write 3k values into
inputChanthen will read values fromoutputChan.Your code blocks on the first of those steps:
outputChanbefore 3k values are succesfully sent toinputChan, so the workers end up stuck onoutputChan <- iafter the first 1k valueinputChan,mainwill get stuck oninputChan <- iafter ~2k valuesOne way to fix this can be to have the producer (
inputChan <- i) and the end consumer (for o := range outputChan {) run in separate goroutines.You can keep one of these actors in the main goroutine, and spin a new one for the other. For example :
https://go.dev/play/p/doBgfkAbyaO
one extra note: the order of actions around signaling
doneis important ; channelsdoneandoutputChanshould only be closed afterwg.Done()indicates that all workers are finished