Go 戈罗季斯正在睡着
我遇到了致命错误:所有goroutine都处于休眠状态-死锁,即使我正在使用缓冲通道并获得结果。但在得到所有结果后,我发现了一个错误Go 戈罗季斯正在睡着,go,concurrency,Go,Concurrency,我遇到了致命错误:所有goroutine都处于休眠状态-死锁,即使我正在使用缓冲通道并获得结果。但在得到所有结果后,我发现了一个错误 package main import ( "fmt" "time" ) func main() { StartJobExample() } var MAX_NUM = 1000 func StartJobExample(){ t1 := time.Now() jobs := m
package main
import (
"fmt"
"time"
)
func main() {
StartJobExample()
}
var MAX_NUM = 1000
func StartJobExample(){
t1 := time.Now()
jobs := make(chan int,MAX_NUM)
result:=make( chan int,MAX_NUM)
go worker(jobs,result)
writeNums(jobs)
for j := range result{
fmt.Println("number read is ",j)
}
close(result)
t2 := time.Now()
fmt.Println("Time taken in operation ",t2.Sub(t1).Seconds())
}
func worker(jobs <-chan int ,result chan<- int){
for i:= range jobs{
result<-addTwo(i)
}
}
func writeNums(jobs chan<- int){
for i:=0;i<MAX_NUM;i++{
fmt.Println("adding job ",i)
jobs<-i
}
close(jobs)
}
func addTwo(i int)int{
return i+2
}
主程序包
进口(
“fmt”
“时间”
)
func main(){
StartJobExample()
}
var MAX_NUM=1000
func StartJobExample(){
t1:=时间。现在()
作业:=制造(成交量,最大数量)
结果:=make(chan int,MAX_NUM)
go worker(工作、结果)
写入枚举(作业)
对于j:=范围结果{
fmt.Println(“读取的数字为”,j)
}
关闭(结果)
t2:=时间。现在()
fmt.Println(“运行所用的时间”,t2.Sub(t1.Seconds())
}
func-worker(jobs您的代码中有几个错误,让我们逐一检查一下
首先,在您的案例中,您并不真正需要缓冲通道,因为它们目前正在帮助掩盖您真正的问题
其次,writeNums
函数应该在一个单独的goroutine中执行。现在,您可以在同一goroutine中的jobs
通道中进行写入,并从result
通道中进行读取(在main
goroutine中),在您的情况下,这必然会产生死锁。此问题通过使用缓冲通道来掩盖。因此,只需执行以下操作:
go writeNums(jobs)
第三,您当前的代码永远不会执行以下操作:
for j := range result{
fmt.Println("number read is ",j)
}
close(result)
这就是在您的示例中产生死锁的原因。result
通道将永远不会关闭,因为close(result)
是在for
循环之后执行的。您应该将此close(result)
放在worker
函数中,在for
循环之后
func worker(jobs <-chan int ,result chan<- int){
for i:= range jobs{
result<-addTwo(i)
}
close(result)
}
在本例中,您使用sync.WaitGroup
同步所有worker
goroutine。首先添加一个单独的goroutine,等待所有worker
goroutine完成(wg.Wait()
)并关闭结果
频道
其次,在创建每个worker
goroutine之前,需要先执行wg.Add(1)
第三,修改worker
函数,以便在从jobs
通道读取作业并写入result
通道后执行wg.Done()
当最后一个worker
goroutine执行wg.Done()
,wg.Wait()
将在其goroutine中取消阻止执行,并执行close(结果)
。是一个完整的工作示例。对于j:=范围结果
在通道结果
关闭时中断循环。通道结果
在循环后关闭。死锁。您最好学会使用gofmt
。如果我通过添加go worker(作业,结果)来增加工作人员数量
Emin的解决方案失败的次数超过1次。任何人都可以通过增加工作人员的数量来尝试它。结果通道将永远不会关闭,因为关闭(结果)是在for循环之后执行的。您应该关闭(结果)在worker函数中,在for循环之后。
这不完全正确。程序将永远不会到达语句close(result)
,因为程序将阻止推入作业
,而这反过来将阻止,因为它的排水器(worker
)将阻止推入结果
,因为在该执行点,其排水器尚未工作。更重要的是,关闭通道意味着将不会有任何进一步的写入,并且对其进行读取可以停止。众所周知,负责写入通道的例程应负责关闭通道为了防止写封闭通道的恐慌。如果我通过添加go-worker(作业,结果)来增加worker的数量
Emin的解决方案失败的次数超过1次。有人能通过增加工人数量来尝试吗?是的,对。有点忘记了他们被缓冲了。我已经到了提问的极限,有人能帮助增加工人数量吗。
func StartJobExample(){
t1 := time.Now()
numberOfWorkers := 5
jobs := make(chan int)
result:=make( chan int)
var wg sync.WaitGroup
//initialize a goroutine for syncing completion for all workers
go func() {
wg.Wait()
close(result)
}()
//initialize all workers
for i :=0; i < numberOfWorkers; i++ {
wg.Add(1)
go worker(&wg, jobs, result, i)
}
// rest of the StartExample function is unchanged
// ...
}
func worker(wg *sync.WaitGroup, jobs <-chan int ,result chan<- int, num int){
for i:= range jobs{
result<-addTwo(i)
}
wg.Done()
fmt.Println("closing worker ", num)
}