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

Design patterns Go-为什么调度goroutine后台工作人员也需要自己的goroutine?,design-patterns,concurrency,go,goroutine,Design Patterns,Concurrency,Go,Goroutine,我正在研究一些Go的并发模式。我研究了如何使用goroutine和输入/输出通道实现后台工作程序,并注意到当我将新作业发送到接收通道(基本上是将新作业排队)时,我必须在goroutine中执行,否则日程安排就会混乱。意思是: 这导致: for ux,jobData:=范围(数据集){ 输入您的ScheduleWorks函数在主goroutine(即运行程序启动的main()函数的函数)中发送,一个值通过输入。一个工作者接收它,并通过输出发送另一个值。但此时没有人从输出接收,因此程序无法继续,主g

我正在研究一些Go的并发模式。我研究了如何使用goroutine和输入/输出通道实现后台工作程序,并注意到当我将新作业发送到接收通道(基本上是将新作业排队)时,我必须在goroutine中执行,否则日程安排就会混乱。意思是:

这导致:
for ux,jobData:=范围(数据集){

输入您的
ScheduleWorks
函数在主goroutine(即运行程序启动的
main()
函数的函数)中发送,一个值通过
输入
。一个
工作者
接收它,并通过
输出
发送另一个值。但此时没有人从
输出
接收,因此程序无法继续,主goroutine将下一个值发送给另一个
工作者


对每个Worker重复此推理。您有
runtime.numpu()
Worker,这可能比
numJobs
小。假设
runtime.numpu()==4
,因此您有4个工作线程。最后,您成功地发送了4个值,每个值对应一个
工作线程
。由于没有人在读取
输出
,所有工作线程都忙于发送,因此他们无法通过
输入
接受更多数据,因此第五个
输入这是因为默认情况下,Go中的所有内容都被阻塞。

当您在无缓冲通道上发送第一个值时,它会阻塞,直到接收器将该值从通道上取下

可以通过添加“容量”来缓冲通道

例如:

make(chan int, 20) // Make a buffered channel of int with capacity 20
发件人:

以元素数表示的容量设置通道中缓冲区的大小。如果容量大于零,则通道是异步的:如果缓冲区未满(发送)或未空(接收),则通信操作在不阻塞的情况下成功,元素按发送顺序接收。如果容量为零或不存在,则只有当发送方和接收方都准备好时,通信才会成功

通过使用缓冲通道而不是非缓冲通道,您可以使原始函数正常工作,但将函数调用包装在goroutine中可能是一种更好的方法,因为它实际上是并发的

From(完整阅读此文档!它可能是Go answers on Stack Overflow中链接最多的文档):

接收器总是阻塞,直到有数据要接收。如果通道未缓冲,发送器阻塞,直到接收器接收到值。如果通道有缓冲区,发送器阻塞,直到值被复制到缓冲区;如果缓冲区已满,这意味着等待某个接收器检索到值

如果您使用缓冲通道,那么您只是在填充通道,继续,然后再次排空。而不是同时进行

例如:

改变

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


请注意,对于此类任务,
sync.WaitGroup
可能是完成任务的另一种方法。也就是说,如果您需要在继续之前处理所有数据


请在同步软件包的文档中阅读:

哇,回答得很好-这真的很清楚。谢谢!
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\n", results)
}

func main() {
    ScheduleWorkers()
}
make(chan int, 20) // Make a buffered channel of int with capacity 20
input, output := make(chan int), make(chan int)
input, output := make(chan int, 20), make(chan int, 20)