Golang使用了WaitGroup,但仍然出现了死锁错误。

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

golang used waitGroup and still ended up with a deadlock error

问题

我正在尝试按照《Go并发编程》一书中的示例实现桥接模式。

  1. func bridge_impl() {
  2. done := make(chan interface{})
  3. defer close(done)
  4. var wg sync.WaitGroup
  5. bridge := func(
  6. done <-chan interface{},
  7. chanStream <-chan <-chan interface{},
  8. ) <-chan interface{} {
  9. valStream := make(chan interface{})
  10. go func() {
  11. wg.Add(1)
  12. defer close(valStream)
  13. for {
  14. var stream <-chan interface{}
  15. select {
  16. case maybeStream, ok := <-chanStream:
  17. fmt.Println("works")
  18. if ok == false {
  19. return
  20. }
  21. stream = maybeStream
  22. case <-done:
  23. return
  24. }
  25. for val := range stream {
  26. select {
  27. case valStream <- val:
  28. case <-done:
  29. }
  30. }
  31. }
  32. }()
  33. return valStream
  34. }
  35. genVals := func() <-chan <-chan interface{} {
  36. chanStream := make(chan (<-chan interface{}))
  37. go func() {
  38. wg.Add(1)
  39. defer close(chanStream)
  40. for i := 0; i < 10; i++ {
  41. stream := make(chan interface{})
  42. stream <- i
  43. close(stream)
  44. chanStream <- stream
  45. }
  46. }()
  47. return chanStream
  48. }
  49. for v := range bridge(done, genVals()) {
  50. fmt.Printf("%v ", v)
  51. }
  52. wg.Wait()
  53. }

然而,我遇到了一个死锁错误all goroutines are asleep - deadlock!。起初,我认为即使在书中的示例中没有实现,我也应该添加一个WaitGroup,但结果仍然出现了相同的错误。

英文:

I'm trying to implement the bridge pattern following Go Concurrency book

  1. func bridge_impl() {
  2. done := make(chan interface{})
  3. defer close(done)
  4. var wg sync.WaitGroup
  5. bridge := func(
  6. done &lt;-chan interface{},
  7. chanStream &lt;-chan &lt;-chan interface{},
  8. ) &lt;-chan interface{} {
  9. valStream := make(chan interface{})
  10. go func() {
  11. wg.Add(1)
  12. defer close(valStream)
  13. for {
  14. var stream &lt;-chan interface{}
  15. select {
  16. case maybeStream, ok := &lt;-chanStream:
  17. fmt.Println(&quot;works&quot;)
  18. if ok == false {
  19. return
  20. }
  21. stream = maybeStream
  22. case &lt;-done:
  23. return
  24. }
  25. for val := range stream {
  26. select {
  27. case valStream &lt;- val:
  28. case &lt;-done:
  29. }
  30. }
  31. }
  32. }()
  33. return valStream
  34. }
  35. genVals := func() &lt;-chan &lt;-chan interface{} {
  36. chanStream := make(chan (&lt;-chan interface{}))
  37. go func() {
  38. wg.Add(1)
  39. defer close(chanStream)
  40. for i := 0; i &lt; 10; i++ {
  41. stream := make(chan interface{})
  42. stream &lt;- i
  43. close(stream)
  44. chanStream &lt;- stream
  45. }
  46. }()
  47. return chanStream
  48. }
  49. for v := range bridge(done, genVals()) {
  50. fmt.Printf(&quot;%v &quot;, v)
  51. }
  52. wg.Wait()
  53. }

However I'm receiving a deadlock errorall goroutines are asleep - deadlock! at first I thought I should add a waitgroup even though it wasn't implemented in the book example but I ended up with the same error

答案1

得分: 2

有两个主要问题。

第一个问题

  1. for i := 0; i < 10; i++ {
  2. stream := make(chan interface{})
  3. stream <- i
  4. close(stream)
  5. chanStream <- stream
  6. }

在创建后向无缓冲通道写入数据,但没有 goroutine 读取。请使用带缓冲的通道或另一个 goroutine。

  1. stream := make(chan interface{}, 1) // 缓冲大小为 1,以避免 `stream <- i` 阻塞

第二个问题
在使用 wg.Add(1) 时没有使用 wg.Done()。你可以在两种情况下都使用 defer

  1. wg.Add(1)
  2. defer wg.Done()
英文:

There are two main issues.
Working example

First issue:

  1. for i := 0; i &lt; 10; i++ {
  2. stream := make(chan interface{})
  3. stream &lt;- i
  4. close(stream)
  5. chanStream &lt;- stream
  6. }

writing to unbuffered channel after creation with no goroutine reading. Use buffered channel or another goroutine.

  1. stream := make(chan interface{}, 1) // buffer size 1 to not block `stream &lt;- i`

Second issue:
Using wg.Add(1) without wg.Done().
You can use defer in both cases.

  1. wg.Add(1)
  2. defer wg.Done()

答案2

得分: 2

根据我理解,你根本不需要使用WaitGroup,只需要重新排列genVals函数循环中的语句顺序即可:

  1. for i := 0; i < 10; i++ {
  2. stream := make(chan interface{})
  3. chanStream <- stream
  4. stream <- i
  5. close(stream)
  6. }

你可以在以下链接中查看代码示例:https://go.dev/play/p/7D9OzrsvZyi

英文:

From what I understand you do not need a WaitGroup at all, you just need to re-order the statements in the genVals function's loop:

  1. for i := 0; i &lt; 10; i++ {
  2. stream := make(chan interface{})
  3. chanStream &lt;- stream
  4. stream &lt;- i
  5. close(stream)
  6. }

https://go.dev/play/p/7D9OzrsvZyi

huangapple
  • 本文由 发表于 2022年3月17日 20:47:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/71512541.html
匿名

发表评论

匿名网友

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

确定