我们有一堆文件要在处理后上传到远程blob商店。
目前,前端(PHP)会创建此类文件的redis列表,并为其提供一个名为JobID的唯一ID。然后,它将唯一ID传递给bean进程管,该进程由Go进程接收。它使用名为Go workers的库以net/http
的方式处理每个作业ID。它接收作业ID,检索redis列表并开始处理文件。
但是,目前一次只处理一个文件。由于这里的操作是I / O绑定,而不是CPU限制,直觉表明每个文件使用goroutine会有好处。
但是,我们希望在失败时重试上传,并跟踪每个作业处理的项目数。我们无法启动未绑定数量的goroutine,因为单个作业可以包含大约10k个要处理的文件,并且在高峰时间每秒可以发送100个这样的作业。对此有什么正确的解决方法?
注意:如果需要,我们可以稍微更改一下技术堆栈(比如换掉beanstalkd)
答案 0 :(得分:2)
您可以使用缓冲的chan
来限制goroutine的数量,其大小为您想要的最大goroutine数量。如果达到最大容量,您可以阻止此chan
。随着你的goroutines结束,他们将释放插槽以允许新的goroutines运行。
示例:
package main
import (
"fmt"
"sync"
)
var (
concurrent = 5
semaphoreChan = make(chan struct{}, concurrent)
)
func doWork(wg *sync.WaitGroup, item int) {
// block while full
semaphoreChan <- struct{}{}
go func() {
defer func() {
// read to release a slot
<-semaphoreChan
wg.Done()
}()
// This is where your work actually gets done
fmt.Println(item)
}()
}
func main() {
// we need this for the example so that we can block until all goroutines finish
var wg sync.WaitGroup
wg.Add(10)
// start the work
for i := 0; i < 10; i++ {
doWork(&wg, i)
}
// block until all work is done
wg.Wait()
}
Go Playground链接:https://play.golang.org/p/jDMYuCe7HV
受到Golang英国会议演讲的启发:https://youtu.be/yeetIgNeIkc?t=1413