Home > Article > Backend Development > What are the causes of deadlocks in Go code using WaitGroups and Buffered Channels?
#php editor Baicao will answer a common question in this article: "What is the reason for deadlock in Go code using WaitGroups and Buffered Channels?" In the Go language , WaitGroups and Buffered Channels are commonly used concurrent programming tools. However, sometimes you may encounter deadlock situations in code that uses them. This article will delve into the causes of deadlocks and provide solutions to help readers avoid this problem. Whether you are a beginner or an experienced Go developer, this article will provide you with valuable information.
Waiting group, buffer channel and deadlock
This code of mine causes a deadlock, but I'm not sure why. I've tried using mutexes in a few different places, closing channels inside and outside separate go routines, but still the same result.
I try to send data through one channel (inputchan) and then read data from another channel (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 the main function is continuous,Firsttry to write the 3k value into inputchan
thenThe value will be read from outputchan
.
Your code will block on the first step:
outputchan
until 3k values are successfully sent to inputchan
, so the worker ends up stuck at outputchan < after the first 1k values ;- i
inputchan
, main
will get stuck at inputchan <- i
One way to solve this problem is to have the producer (inputchan <- i
) and the final consumer (for o := range outputchan {
) in separate goroutines in operation.
You can keep one of these actors in the main goroutine and spin up a new actor for the other one. For example:
go func(inputchan chan<- int){ for i := 0; i < 3000; i++ { inputchan <- i } close(inputchan) }(inputchan) done := make(chan struct{}) go func() { close(done) // close(inputchan) // i chose to close inputchan above, don't close it twice close(outputchan) wg.wait() }() ...
https://www.php.cn/link/80e4c54699b5b8cf8c67dd496909fceb
An additional note: the order of operations surrounding signaling done
is important; channels done
and outputchan
can only be used on wg.done ()
Instruct all workers to close when finished
// it is best to close inputChan next to the code that controls // when its input is complete. close(inputChan) // If you had several producers writing to the same channel, you // would probably have to add a separate waitgroup to handle closing, // much like you did for your workers go func() { wg.Wait() // the two following actions must happen *after* workers have // completed close(done) close(outputChan) }()
The above is the detailed content of What are the causes of deadlocks in Go code using WaitGroups and Buffered Channels?. For more information, please follow other related articles on the PHP Chinese website!