如何避免同时打印字母数字的死锁

How to avoid deadlock in printing alphanumeric numbers concurrently

我是 golang 的新手,我只想打印出 10 个字母数字组合数字范围和字符范围的元素。

我决定同时进行,但我 运行 遇到了有关死锁的错误。

package main

import (
    "fmt"
    "math/rand"
    "sync"
    "time"
)

type alphanumeric struct {
    anAlphabet string
    aNumber    string
}

func (someStruct alphanumeric) pairAlphanumeric() string {

    return someStruct.aNumber + someStruct.anAlphabet

}

func main() {

    var wg sync.WaitGroup

    numbers := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}
    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"}

    //var aleph alphanumeric
    //var alephS []alphanumeric

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

    wg.Wait()
} // end of main()

func makeAleph(numbers []string, alphabets []string) {

    var aleph alphanumeric

    aleph.anAlphabet = aNum(numbers)
    aleph.aNumber = anAlph(alphabets)

    fmt.Println(aleph.pairAlphanumeric())

    //return aleph.pairAlphanumeric()
}

func randomIndex() int {
    randTime := time.Time.UnixNano(time.Now())

    rand.Seed(randTime)

    return rand.Intn(10)
}

func aNum(numbers []string) string {

    return numbers[randomIndex()]

}

func anAlph(alphabets []string) string {

    return alphabets[randomIndex()]

}

正确打印所需数字后抛出的错误是:

❯ go run aleph.go
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc42000e2dc)
    /Users/eklavya/.gvm/gos/go1.8/src/runtime/sema.go:47 +0x34
sync.(*WaitGroup).Wait(0xc42000e2d0)
    /Users/eklavya/.gvm/gos/go1.8/src/sync/waitgroup.go:131 +0x7a
main.main()
    /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:38 +0x14c

goroutine 5 [chan receive (nil chan)]:
main.makeAleph(0xc420084000, 0xa, 0xa, 0xc420001520, 0x1a, 0x1a)
    /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:61 +0x134
main.main.func1(0xc42000e2d0, 0xc420084000, 0xa, 0xa, 0xc420001520, 0x1a, 0x1a)
    /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:35 +0x94
created by main.main
    /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:37 +0x13e

goroutine 6 [chan send (nil chan)]:
main.aNum(0x0, 0xc420084000, 0xa, 0xa)
    /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:79 +0x5b
main.makeAleph.func1(0xc42000e2e0, 0x0, 0xc420084000, 0xa, 0xa)
    /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:51 +0x73
created by main.makeAleph
    /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:52 +0xad

goroutine 7 [chan send (nil chan)]:
main.anAlph(0x0, 0xc420001520, 0x1a, 0x1a)
    /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:85 +0x5b
main.makeAleph.func2(0xc42000e2e0, 0x0, 0xc420001520, 0x1a, 0x1a)
    /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:56 +0x73
created by main.makeAleph
    /Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:57 +0xff
exit status 2

如何避免同时打印字母数字时出现死锁?

您当前的代码根本不是并发的。除了 main.

之外,所有字母数字代码都是在您正在创建的唯一 goroutine 中的单个 for 循环 运行 中按顺序生成的

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

在您的代码中,您只调用了一次 wg.Done。这意味着一旦你的 goroutine returns 和对 wg.Wait 的调用将永远不会 return,waitgroup 计数器将保持在 25,因为没有其他 goroutine 是 运行 可以通过使进一步调用 wg.Done.

为了(模糊地)得到你想要的,你可以尝试这样的事情:

// ...

n := 10 // number of codes you want to print

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 returns,wg.Done 就会被调用。总共调用了 n wg.Done 次,允许在 main 中完成对 wg.Wait 的调用。