我正在研究麻省理工学院6.824 - lab1(第三部分)并对一个(迷你)mapreduce的调度程序感到困惑:
var wg sync.WaitGroup
for i := 0; i < ntasks; i++ {
task_arg := DoTaskArgs{ JobName: jobName, File: mapFiles[i], Phase: phase, TaskNumber: i, NumOtherPhase: n_other }
//not so relevant
wg.Add(1)
go func() {
defer wg.Done()
reg_worker := <- registerChan
call(reg_worker, "Worker.DoTask", task_arg, nil)
go func() { registerChan <- reg_worker }()
//registerChan <- reg_worker
}()
}
wg.Wait()
这个程序
call
registerChan
)部署100个任务
wg.Add()
,wg.Done
,wg.Wait()
同步如何调用schedule
(https://github.com/WentaoZero/mini-mapreduce/blob/master/master.go#L84):
ch := make(chan string)
go mr.forwardRegistrations(ch)
schedule(mr.jobName, mr.files, mr.nReduce, phase, ch)
registerChan
未缓冲。
我尝试在第goroutine
行删除go func() { registerChan <- reg_worker }()
以进行此操作:registerChan <- reg_worker
程序在完成50多项任务后陷入困境。我想它证明了goroutine正在工作,但我不明白为什么它会卡住。
registerChan <- reg_worker
是用goroutine编写的,为什么有必要用另一个goroutine包装它?
我不认为系统的其余部分是相关的,所以我不会在这里发布。如果需要,您可以查看https://github.com/WentaoZero/mini-mapreduce。此调度程序从https://github.com/WentaoZero/mini-mapreduce/blob/master/schedule.go
中选取答案 0 :(得分:0)
除非已收到,否则将阻止发送至无缓冲频道。在您的情况下,您有100个任务,这意味着reg_worker := <- registerChan
和registerChan <- reg_worker
将被调用100次。似乎发送/接收是平衡的,对吧?
但是,你仍然有2名工人!代码中某处必须有registerChan <- new_worker
(最有可能是mr.forwardRegistrations(ch)
),应该被调用2次!
因此,您在无缓冲频道上发送的内容比接收的多两个,因此最后2 registerChan <- reg_worker
被阻止,然后defer wg.Done()
和wg.Wait()
也会被屏蔽!
要验证它,您可以这样调试:
defer wg.Done()
reg_worker := <-registerChan
call(reg_worker, "Worker.DoTask", task_arg, nil)
fmt.Println("### start sending to registerChan")
registerChan <- reg_worker
fmt.Println("### send done")
只计算这两个句子的出现次数。它应该是100和98!