dqrb4228 2014-03-24 10:35
浏览 44
已采纳

开始-为什么调度goroutine后台工作人员也需要自己的goroutine?

I'm working on picking up a few of concurrency patterns of Go. I looked at implementing background workers using goroutines and input/output channels, and noticed that when I sending new jobs to the receiving channel (essentially enqueuing new jobs) I have to do it in a goroutine or the scheduling gets messed up. Meaning:

This crashes:

for _, jobData := range(dataSet) {
    input <- jobData
}

This works:

go func() {
    for _, jobData := range(dataSet) {
        input <- jobData
    }
}()

For something more concrete, I played with some nonsense code (here it is in go playground):

package main

import (
    "log"
    "runtime"
)

func doWork(data int) (result int) {
    // ... some 'heavy' computation
    result = data * data
    return
}

// do the processing of the input and return
// results on the output channel
func Worker(input, output chan int) {
    for data := range input {
        output <- doWork(data)
    }
}

func ScheduleWorkers() {

    input, output := make(chan int), make(chan int)

    for i := 0 ; i < runtime.NumCPU() ; i++ {
        go Worker(input, output)
    }

    numJobs := 20

    // THIS DOESN'T WORK
    // and crashes the program
    /*
    for i := 0 ; i < numJobs ; i++ {
        input <- i
    }
    */

    // THIS DOES
    go func() {
        for i := 0 ; i < numJobs ; i++ {
            input <- i
        }
    }()

    results := []int{}
    for i := 0 ; i < numJobs ; i++ {
        // read off results
        result := <-output
        results = append(results, result)
        // do stuff...
    }

    log.Printf("Result: %#v
", results)
}

func main() {
    ScheduleWorkers()
}

I'm trying to wrap my head around this subtle difference - help is appreciated. Thanks.

  • 写回答

3条回答 默认 最新

  • dsgo31121 2014-03-24 11:01
    关注

    Your ScheduleWorks function sends, in the main goroutine (ie. the one that runs the main() function, in which the program starts), a value via input. A Worker receives it, and sends another value via output. But there is nobody receiving from output at that point, so the program can't go on, and the main goroutine sends the next value to another Worker.

    Repeat this reasoning for each Worker. You have runtime.NumCPU() workers, that probably is less than numJobs. Let's say that runtime.NumCPU() == 4, so you have 4 workers. At the end, you have successfully sent 4 values, each one to one Worker. Since nobody is reading from output, all Workers are busy trying to send, so they can't accept more data via input, so the fifth input <- i will hang. At this point every goroutine is waiting; that's the deadlock.

    enter image description here

    You will notice that, if you launch 20 or more Workers instead of runtime.NumCPU(), the program works. That's because the main goroutine can send everything that it wants via input, since there are enough workers to receive them.

    If, instead of all of this, you put the input <- i loop in another goroutine, as in your successful example, the main goroutine (in which ScheduleWorks runs) can go on and start reading from output. So, each time this new goroutine sends a value, the worker sends another via output, the main goroutine gets this output, and the worker can receive another value. Nobody waits, and the program succeeds.

    enter image description here

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥50 yalmip+Gurobi
  • ¥20 win10修改放大文本以及缩放与布局后蓝屏无法正常进入桌面
  • ¥15 angular开发过程中,想要读取模型文件,即图1的335行,会报404错误(如图2)。但我的springboot里配置了静态资源文件,如图3。且在该地址下我有模型文件如图4,请问该问题该如何解决呢?
  • ¥15 itunes恢复数据最后一步发生错误
  • ¥15 关于#windows#的问题:2024年5月15日的win11更新后资源管理器没有地址栏了顶部的地址栏和文件搜索都消失了
  • ¥100 H5网页如何调用微信扫一扫功能?
  • ¥15 讲解电路图,付费求解
  • ¥15 有偿请教计算电磁学的问题涉及到空间中时域UTD和FDTD算法结合的
  • ¥15 vite打包后,页面出现h.createElement is not a function,但本地运行正常
  • ¥15 Java,消息推送配置