我正在研究麻省理工学院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将100个任务部署到2个工作人员(使用registerChan )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多个任务后,程序就被卡住了。我想这证明了戈鲁蒂河是起作用的,但我不明白它为什么会卡住。
registerChan <- reg_worker是用goroutine编写的,为什么有必要用另一个goroutine来包装它呢?
我不认为系统的其他部分是相关的,所以我不会在这里发布。如果需要,您可以检查https://github.com/WentaoZero/mini-mapreduce。这个调度程序是从https://github.com/WentaoZero/mini-mapreduce/blob/master/schedule.go中选择的。
发布于 2017-07-12 03:16:43
由于registerChan没有缓冲,所以内部的goroutine是非常必要的!
除非接收到未缓冲的信道,否则发送将被阻塞。在您的例子中,您有100个任务,这意味着reg_worker := <- registerChan和registerChan <- reg_worker将被调用100次。似乎发送/接收是平衡的,对吧?
但是,你还有两个工人!代码中一定有类似于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!
https://stackoverflow.com/questions/45030652
复制相似问题