如何避免同时打印字母数字的死锁
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
的调用。
我是 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
.
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
的调用。