Design patterns Go-为什么调度goroutine后台工作人员也需要自己的goroutine?
我正在研究一些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
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)