预期输出以及工作池中的死锁问题

huangapple go评论130阅读模式
英文:

Expected output as well as deadlock in a worker pool

问题

我正在学习Go语言并发,并编写了一个必备的工作池示例,其中有N个工作和M个工作者(N > M)。我遇到了一个死锁问题(all goroutines are asleep),我无法解决;然而,在死锁发生之前,我也得到了预期的输出,这让我更加困惑。请问有人可以指出我做错了什么吗?

我的代码如下:

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. // 使用通道和WaitGroup实现一个简单的工作池。
  7. // 我们的工作者从输入通道中读取整数,并将其平方写入输出通道。
  8. func addJobs(jobsCh chan<- int, wg *sync.WaitGroup) {
  9. // 100个要处理的数字(工作)
  10. for i := 1; i < 101; i++ {
  11. jobsCh <- i
  12. }
  13. wg.Done()
  14. }
  15. func worker(jobsCh <-chan int, resultsCh chan<- int, wg2 *sync.WaitGroup) {
  16. for num := range jobsCh {
  17. resultsCh <- num * num
  18. }
  19. wg2.Done()
  20. }
  21. func addWorkers(jobsCh <-chan int, resultsCh chan<- int, wg *sync.WaitGroup) {
  22. var wg2 sync.WaitGroup
  23. // 10个工作者
  24. for i := 0; i < 10; i++ {
  25. wg2.Add(1)
  26. go worker(jobsCh, resultsCh, &wg2)
  27. }
  28. wg.Done()
  29. }
  30. func readResults(resultsCh <-chan int, wg *sync.WaitGroup) {
  31. for sq := range resultsCh {
  32. fmt.Printf("%v ", sq)
  33. }
  34. wg.Done()
  35. }
  36. func main() {
  37. var wg sync.WaitGroup
  38. jobsCh := make(chan int)
  39. resultsCh := make(chan int)
  40. wg.Add(1)
  41. go addJobs(jobsCh, &wg)
  42. wg.Add(1)
  43. go addWorkers(jobsCh, resultsCh, &wg)
  44. wg.Add(1)
  45. go readResults(resultsCh, &wg)
  46. wg.Wait()
  47. }

这会按预期打印数字的平方(顺序随机),但也会遇到死锁问题。请参考这个 playground 链接。 预期输出以及工作池中的死锁问题

英文:

I'm learning Go concurrency and wrote the obligatory worker pool example, where there are N pieces of work and M workers (N > M). I'm running into a deadlock (all goroutines are asleep), which I can't figure out; however, I'm also getting the expected output before the deadlock occurs, which has me even more confused. Can someone please point out the things I'm doing wrong?

My code is this:

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;sync&quot;
  5. )
  6. // A simple worker pool implementation using channels and WaitGroups.
  7. // Our workers simply read from a channel of integers from an input
  8. // channel and write their squares to an output channel.
  9. func addJobs(jobsCh chan&lt;- int, wg *sync.WaitGroup) {
  10. // 100 numbers to crunch (jobs)
  11. for i := 1; i &lt; 101; i++ {
  12. jobsCh &lt;- i
  13. }
  14. wg.Done()
  15. }
  16. func worker(jobsCh &lt;-chan int, resultsCh chan&lt;- int, wg2 *sync.WaitGroup) {
  17. for num := range jobsCh {
  18. resultsCh &lt;- num * num
  19. }
  20. wg2.Done()
  21. }
  22. func addWorkers(jobsCh &lt;-chan int, resultsCh chan&lt;- int, wg *sync.WaitGroup) {
  23. var wg2 sync.WaitGroup
  24. // 10 workers
  25. for i := 0; i &lt; 10; i++ {
  26. wg2.Add(1)
  27. go worker(jobsCh, resultsCh, &amp;wg2)
  28. }
  29. wg.Done()
  30. }
  31. func readResults(resultsCh &lt;-chan int, wg *sync.WaitGroup) {
  32. for sq := range resultsCh {
  33. fmt.Printf(&quot;%v &quot;, sq)
  34. }
  35. wg.Done()
  36. }
  37. func main() {
  38. var wg sync.WaitGroup
  39. jobsCh := make(chan int)
  40. resultsCh := make(chan int)
  41. wg.Add(1)
  42. go addJobs(jobsCh, &amp;wg)
  43. wg.Add(1)
  44. go addWorkers(jobsCh, resultsCh, &amp;wg)
  45. wg.Add(1)
  46. go readResults(resultsCh, &amp;wg)
  47. wg.Wait()
  48. }

This prints the squares of the numbers (in random order), as expected, but also runs into a deadlock. Please see this playground link. 预期输出以及工作池中的死锁问题

答案1

得分: 2

关闭jobsCh以使工作线程退出:

  1. func addJobs(jobsCh chan<- int, wg *sync.WaitGroup) {
  2. // 100个要处理的数字(工作)
  3. for i := 1; i < 101; i++ {
  4. jobsCh <- i
  5. }
  6. close(jobsCh) // <-- 添加这一行
  7. wg.Done()
  8. }

当工作线程完成后,关闭resultsCh以使结果循环退出:

  1. func addWorkers(jobsCh <-chan int, resultsCh chan<- int, wg *sync.WaitGroup) {
  2. var wg2 sync.WaitGroup
  3. // 10个工作线程
  4. for i := 0; i < 10; i++ {
  5. wg2.Add(1)
  6. go worker(jobsCh, resultsCh, &wg2)
  7. }
  8. wg2.Wait() // <-- 添加这一行
  9. close(resultsCh) // 和这一行
  10. wg.Done()
  11. }
英文:

Close jobsCh to cause workers to exit:

  1. func addJobs(jobsCh chan&lt;- int, wg *sync.WaitGroup) {
  2. // 100 numbers to crunch (jobs)
  3. for i := 1; i &lt; 101; i++ {
  4. jobsCh &lt;- i
  5. }
  6. close(jobsCh) // &lt;-- add this line
  7. wg.Done()
  8. }

After workers are done, close resultsCh to cause results loop to exit:

  1. func addWorkers(jobsCh &lt;-chan int, resultsCh chan&lt;- int, wg *sync.WaitGroup) {
  2. var wg2 sync.WaitGroup
  3. // 10 workers
  4. for i := 0; i &lt; 10; i++ {
  5. wg2.Add(1)
  6. go worker(jobsCh, resultsCh, &amp;wg2)
  7. }
  8. wg2.Wait() // &lt;-- add this line
  9. close(resultsCh) // and this line
  10. wg.Done()
  11. }

huangapple
  • 本文由 发表于 2022年7月18日 22:52:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/73024321.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定