为什么需要嵌套goroutine?

时间:2017-07-11 09:32:03

标签: go goroutine

我正在研究麻省理工学院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()

这个程序

  1. 从通道call
  2. 向100名工作人员(registerChan)部署100个任务
  3. 任务完成后将工作人员重新置于频道
  4. wg.Add()wg.Donewg.Wait()同步
  5. 如何调用schedulehttps://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

    中选取

1 个答案:

答案 0 :(得分:0)

由于registerChan没有被缓冲,所以内部goroutine是非常有用的!

除非已收到,否则将阻止发送至无缓冲频道。在您的情况下,您有100个任务,这意味着reg_worker := <- registerChanregisterChan <- 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!