我通过建立一个1000名工人的工人池来玩弄渠道。目前我收到以下错误:
fatal error: all goroutines are asleep - deadlock!
这是我的代码:
package main
import "fmt"
import "time"
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Println("worker", id, "started job", j)
time.Sleep(time.Second)
fmt.Println("worker", id, "finished job", j)
results <- j * 2
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
for w := 1; w <= 1000; w++ {
go worker(w, jobs, results)
}
for j := 1; j < 1000000; j++ {
jobs <- j
}
close(jobs)
fmt.Println("==========CLOSED==============")
for i:=0;i<len(results);i++ {
<-results
}
}
为什么会这样?我还是新手,我希望能够理解这一点。
答案 0 :(得分:3)
虽然托马斯的答案基本上是正确的,但我发布了我的版本,这是IMO更好的Go,也适用于无缓冲的频道:
func main() {
jobs := make(chan int)
results := make(chan int)
var wg sync.WaitGroup
// you could init the WaitGroup's count here with one call but this is error
// prone - if you change the loop's size you could forget to change the
// WG's count. So call wg.Add in loop
//wg.Add(1000)
for w := 1; w <= 1000; w++ {
wg.Add(1)
go func() {
defer wg.Done()
worker(w, jobs, results)
}()
}
go func() {
for j := 1; j < 2000; j++ {
jobs <- j
}
close(jobs)
fmt.Println("==========CLOSED==============")
}()
// in this gorutine we wait until all "producer" routines are done
// then close the results channel so that the consumer loop stops
go func() {
wg.Wait()
close(results)
}()
for i := range results {
fmt.Print(i, " ")
}
fmt.Println("==========DONE==============")
}
答案 1 :(得分:1)
以下代码:
for j := 1; j < 1000000; j++ {
jobs <- j
}
应该在一个单独的goroutine中运行,因为所有的工作人员都会阻止等待主gorourine在结果通道上接收,而主要的goroutine会卡在循环中。
答案 2 :(得分:1)
问题在于您的频道正在填满。 main()
例程尝试在读取任何结果之前将所有作业放入jobs
频道。但是results
频道在对频道的任何写入都会阻止之前只有100个结果的空间,所以所有工作人员最终都会阻止等待这个频道中的空间 - 永远不会来的空间,因为main()
有尚未开始从results
开始阅读。
要快速解决此问题,您可以使jobs
足够大以容纳所有作业,因此main()
功能可以继续读取阶段;或者你可以使results
足够大以容纳所有结果,这样工人就可以输出结果而不会阻塞。
更好的做法是让另一个goroutine填满jobs
队列,因此main()
可以直接阅读结果:
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
for w := 1; w <= 1000; w++ {
go worker(w, jobs, results)
}
go func() {
for j := 1; j < 1000000; j++ {
jobs <- j
}
close(jobs)
fmt.Println("==========CLOSED==============")
}
for i := 1; i < 1000000; i++ {
<-results
}
}
请注意,我必须将最终的for
循环更改为固定的迭代次数,否则它可能会在读取所有结果之前终止。
答案 3 :(得分:0)
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for j := range jobs {
fmt.Println("worker", id, "started job", j)
time.Sleep(time.Millisecond * time.Duration(10))
fmt.Println("worker", id, "finished job", j)
results <- j * 2
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
wg := new(sync.WaitGroup)
wg.Add(1000)
for w := 1; w <= 1000; w++ {
go worker(w, jobs, results, wg)
}
go func() {
wg.Wait()
close(results)
}()
go func() {
for j := 1; j < 1000000; j++ {
jobs <- j
}
close(jobs)
}()
sum := 0
for v := range results {
sum += v
}
fmt.Println("==========CLOSED==============")
fmt.Println("sum", sum)
}