如何避免并发打印字母数字时的死锁问题

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

How to avoid deadlock in printing alphanumeric numbers concurrently

问题

我是你的中文翻译助手,以下是你要翻译的内容:

我刚开始学习golang,我希望打印出10个由数字范围和字符范围组合而成的字母数字串。

我决定使用并发来实现,但是我遇到了一个关于死锁的错误。

  1. package main
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "sync"
  6. "time"
  7. )
  8. type alphanumeric struct {
  9. anAlphabet string
  10. aNumber string
  11. }
  12. func (someStruct alphanumeric) pairAlphanumeric() string {
  13. return someStruct.aNumber + someStruct.anAlphabet
  14. }
  15. func main() {
  16. var wg sync.WaitGroup
  17. numbers := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}
  18. alphabets := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}
  19. wg.Add(len(alphabets))
  20. go func(numbers []string, alphabets []string) {
  21. defer wg.Done()
  22. for i := 0; i < 10; i++ {
  23. makeAleph(numbers, alphabets)
  24. }
  25. }(numbers, alphabets)
  26. wg.Wait()
  27. }
  28. func makeAleph(numbers []string, alphabets []string) {
  29. var aleph alphanumeric
  30. aleph.anAlphabet = aNum(numbers)
  31. aleph.aNumber = anAlph(alphabets)
  32. fmt.Println(aleph.pairAlphanumeric())
  33. }
  34. func randomIndex() int {
  35. randTime := time.Time.UnixNano(time.Now())
  36. rand.Seed(randTime)
  37. return rand.Intn(10)
  38. }
  39. func aNum(numbers []string) string {
  40. return numbers[randomIndex()]
  41. }
  42. func anAlph(alphabets []string) string {
  43. return alphabets[randomIndex()]
  44. }

在正确打印所需的数字后,它抛出以下错误:

  1. go run aleph.go
  2. fatal error: all goroutines are asleep - deadlock!
  3. goroutine 1 [semacquire]:
  4. sync.runtime_Semacquire(0xc42000e2dc)
  5. /Users/eklavya/.gvm/gos/go1.8/src/runtime/sema.go:47 +0x34
  6. sync.(*WaitGroup).Wait(0xc42000e2d0)
  7. /Users/eklavya/.gvm/gos/go1.8/src/sync/waitgroup.go:131 +0x7a
  8. main.main()
  9. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:38 +0x14c
  10. goroutine 5 [chan receive (nil chan)]:
  11. main.makeAleph(0xc420084000, 0xa, 0xa, 0xc420001520, 0x1a, 0x1a)
  12. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:61 +0x134
  13. main.main.func1(0xc42000e2d0, 0xc420084000, 0xa, 0xa, 0xc420001520, 0x1a, 0x1a)
  14. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:35 +0x94
  15. created by main.main
  16. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:37 +0x13e
  17. goroutine 6 [chan send (nil chan)]:
  18. main.aNum(0x0, 0xc420084000, 0xa, 0xa)
  19. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:79 +0x5b
  20. main.makeAleph.func1(0xc42000e2e0, 0x0, 0xc420084000, 0xa, 0xa)
  21. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:51 +0x73
  22. created by main.makeAleph
  23. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:52 +0xad
  24. goroutine 7 [chan send (nil chan)]:
  25. main.anAlph(0x0, 0xc420001520, 0x1a, 0x1a)
  26. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:85 +0x5b
  27. main.makeAleph.func2(0xc42000e2e0, 0x0, 0xc420001520, 0x1a, 0x1a)
  28. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:56 +0x73
  29. created by main.makeAleph
  30. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:57 +0xff
  31. exit status 2

如何避免在并发打印字母数字时发生死锁?

英文:

I'm new to golang and I just wish to print out 10 alphanumeric numbers combining elements from numeber-range and character-range.

I decided to do it concurrently, but I've been running into an error regarding deadlock.

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;math/rand&quot;
  5. &quot;sync&quot;
  6. &quot;time&quot;
  7. )
  8. type alphanumeric struct {
  9. anAlphabet string
  10. aNumber string
  11. }
  12. func (someStruct alphanumeric) pairAlphanumeric() string {
  13. return someStruct.aNumber + someStruct.anAlphabet
  14. }
  15. func main() {
  16. var wg sync.WaitGroup
  17. numbers := []string{&quot;1&quot;, &quot;2&quot;, &quot;3&quot;, &quot;4&quot;, &quot;5&quot;, &quot;6&quot;, &quot;7&quot;, &quot;8&quot;, &quot;9&quot;, &quot;10&quot;}
  18. alphabets := []string{&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;, &quot;e&quot;, &quot;f&quot;, &quot;g&quot;, &quot;h&quot;, &quot;i&quot;, &quot;j&quot;, &quot;k&quot;, &quot;l&quot;, &quot;m&quot;, &quot;n&quot;, &quot;o&quot;, &quot;p&quot;, &quot;q&quot;, &quot;r&quot;, &quot;s&quot;, &quot;t&quot;, &quot;u&quot;, &quot;v&quot;, &quot;w&quot;, &quot;x&quot;, &quot;y&quot;, &quot;z&quot;}
  19. //var aleph alphanumeric
  20. //var alephS []alphanumeric
  21. wg.Add(len(alphabets))
  22. go func(numbers []string, alphabets []string) {
  23. defer wg.Done()
  24. for i := 0; i &lt; 10; i++ {
  25. makeAleph(numbers, alphabets)
  26. }
  27. }(numbers, alphabets)
  28. wg.Wait()
  29. } // end of main()
  30. func makeAleph(numbers []string, alphabets []string) {
  31. var aleph alphanumeric
  32. aleph.anAlphabet = aNum(numbers)
  33. aleph.aNumber = anAlph(alphabets)
  34. fmt.Println(aleph.pairAlphanumeric())
  35. //return aleph.pairAlphanumeric()
  36. }
  37. func randomIndex() int {
  38. randTime := time.Time.UnixNano(time.Now())
  39. rand.Seed(randTime)
  40. return rand.Intn(10)
  41. }
  42. func aNum(numbers []string) string {
  43. return numbers[randomIndex()]
  44. }
  45. func anAlph(alphabets []string) string {
  46. return alphabets[randomIndex()]
  47. }

And the error that it throws after printing the required numbers correctly is:

  1. go run aleph.go
  2. fatal error: all goroutines are asleep - deadlock!
  3. goroutine 1 [semacquire]:
  4. sync.runtime_Semacquire(0xc42000e2dc)
  5. /Users/eklavya/.gvm/gos/go1.8/src/runtime/sema.go:47 +0x34
  6. sync.(*WaitGroup).Wait(0xc42000e2d0)
  7. /Users/eklavya/.gvm/gos/go1.8/src/sync/waitgroup.go:131 +0x7a
  8. main.main()
  9. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:38 +0x14c
  10. goroutine 5 [chan receive (nil chan)]:
  11. main.makeAleph(0xc420084000, 0xa, 0xa, 0xc420001520, 0x1a, 0x1a)
  12. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:61 +0x134
  13. main.main.func1(0xc42000e2d0, 0xc420084000, 0xa, 0xa, 0xc420001520, 0x1a, 0x1a)
  14. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:35 +0x94
  15. created by main.main
  16. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:37 +0x13e
  17. goroutine 6 [chan send (nil chan)]:
  18. main.aNum(0x0, 0xc420084000, 0xa, 0xa)
  19. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:79 +0x5b
  20. main.makeAleph.func1(0xc42000e2e0, 0x0, 0xc420084000, 0xa, 0xa)
  21. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:51 +0x73
  22. created by main.makeAleph
  23. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:52 +0xad
  24. goroutine 7 [chan send (nil chan)]:
  25. main.anAlph(0x0, 0xc420001520, 0x1a, 0x1a)
  26. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:85 +0x5b
  27. main.makeAleph.func2(0xc42000e2e0, 0x0, 0xc420001520, 0x1a, 0x1a)
  28. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:56 +0x73
  29. created by main.makeAleph
  30. /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:57 +0xff
  31. exit status 2

How can I avoid deadlock in printing alphanumeric numbers concurrently?

答案1

得分: 0

你当前的代码根本不是并发的。所有的字母数字代码都是在一个单独的for循环中按顺序生成的,该循环在除了main之外的唯一goroutine中运行。

你将len(alphabets) == 26添加到了wg.Wait中。这意味着你需要调用26次wg.Done才能完成对wg.Wait的调用。每次调用wg.Done都会将等待组计数器减一。

在你的代码中,你只调用了一次wg.Done。这意味着一旦你的goroutine返回,等待组计数器就会保持在25,而调用wg.Wait将永远不会返回,因为没有其他的goroutine在运行,也就无法通过进一步调用wg.Done来减少等待组计数器。

为了(模糊地)实现你想要的效果,你可以尝试像这样做:

// ...

n := 10 // 你想要打印的代码数量

wg.Add(n)

for i := 0; i < n; i++ {
go func(numbers []string, alphabets []string) {
defer wg.Done()
makeAleph(numbers, alphabets)
}(numbers, alphabets)
}

wg.Wait()

// ...

现在,将会生成n个goroutine,每个goroutine负责通过调用makeAleph打印一个代码。一旦一个goroutine返回,就会调用wg.Done。总共调用nwg.Done,允许在main中调用wg.Wait完成。

英文:

Your current code is not concurrent at all. All the alphanumeric codes are generated sequentially in a single for loop running in the sole goroutine you are creating besides main.

You are adding len(alphabets) == 26 to wg.Wait. That means you need to call 26 wg.Done for the call to wg.Wait to complete. Each wg.Done call reduces the waitgroup counter by one.

In your code, you are calling wg.Done only once. That means waitgroup counter stays at 25 once your goroutine returns and the call to wg.Wait would never return since no other goroutine is running that may reduce the waitgroup counter by making further calls to wg.Done.

To (vaguely) get what you want, you can try something like this:

  1. // ...
  2. n := 10 // number of codes you want to print
  3. wg.Add(n)
  4. for i := 0; i &lt; n; i++ {
  5. go func(numbers []string, alphabets []string) {
  6. defer wg.Done()
  7. makeAleph(numbers, alphabets)
  8. }(numbers, alphabets)
  9. wg.Wait()
  10. // ...

Now, n goroutines will be spawned, each responsible for printing one code by calling makeAleph. As soon as a goroutine returns, wg.Done is called. A total n wg.Dones are called allowing call to wg.Wait in main to complete.

huangapple
  • 本文由 发表于 2017年5月17日 14:33:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/44017241.html
匿名

发表评论

匿名网友

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

确定