遍历方式一旦换成range的方式遍历,就会报deadlock的错,为什么呀?
来源:11-2 使用Channel等待任务结束

Antgan
2019-03-15
package main
import (
"fmt"
"sync"
)
type worker struct {
id int
c chan int
wg *sync.WaitGroup
}
func createWorker(id int, wg *sync.WaitGroup) worker {
c := make(chan int)
return worker{id, c, wg}
}
func (worker *worker) doWork() {
for v := range worker.c {
fmt.Printf("Worker %d do work: %c\n", worker.id, v)
worker.wg.Done()
}
}
func main() {
var wg sync.WaitGroup
var workers [10] worker
//init worker
for i := 0; i < 10; i++ {
workers[i] = createWorker(i, &wg)
}
//Do work
wg.Add(10)
//for i := 0; i < 10; i++ {
// go workers[i].doWork()
//}
//一旦换成range的方式遍历,就会报deadlock的错,为什么呀?
for _, worker := range workers{
go worker.doWork()
}
//Send data
for i := 0; i < 10; i++ {
workers[i].c <- 'a' + i
}
wg.Wait()
}
一旦换成range的方式遍历,就会报deadlock的错,为什么呀?
写回答
1回答
-
ccmouse
2019-03-18
是的。go的for range有一个坑,就是这个worker整个循环过程中只有一个,它不断的被赋值为workers里面的worker。使用了go worker.doWork(),异步的调用了doWork函数,导致这个for循环很快走完,worker被赋值为workers[9]。我们可以把doWork里的worker打印出来看一下,的确是10次对workers[9]的调用。
用range的做法是利用函数传参来复制一份
for _, w:= range workers{
go func(w worker) {
w.doWork()
}(w)
}这样就可以。
042022-02-14
相似问题