通过缓冲通道(Golang)限制并发执行进程的数量
意图: 我正在寻找一种并行运行os级shell命令的方法,但要小心不要影响CPU,我想知道缓冲通道是否适合这个用例 实施: 创建一系列具有模拟运行时持续时间的通过缓冲通道(Golang)限制并发执行进程的数量,go,concurrency,channel,Go,Concurrency,Channel,意图: 我正在寻找一种并行运行os级shell命令的方法,但要小心不要影响CPU,我想知道缓冲通道是否适合这个用例 实施: 创建一系列具有模拟运行时持续时间的作业s。将这些作业发送到一个队列,该队列将将它们分派到运行的缓冲通道上,该通道由EXEC\u THROTTLE限制 意见: 这“起作用”(就编译和运行而言),但我想知道缓冲区是否按照指定的方式工作(请参阅“Intent”),以限制并行运行的进程数量 免责声明: 现在,我意识到新手往往会过度使用频道,但我觉得这种对洞察力的要求是诚实的,因为我
作业
s。将这些作业发送到一个队列,该队列将将它们分派到运行
的缓冲通道上,该通道由EXEC\u THROTTLE
限制
意见:
这“起作用”(就编译和运行而言),但我想知道缓冲区是否按照指定的方式工作(请参阅“Intent”),以限制并行运行的进程数量
免责声明:
现在,我意识到新手往往会过度使用频道,但我觉得这种对洞察力的要求是诚实的,因为我至少克制了自己使用了sync.WaitGroup
。请原谅这个有点像玩具的例子,但所有的洞察力都将受到赞赏
主程序包
进口(
//“os/exec”
“日志”
“数学/兰德”
“strconv”
“同步”
“时间”
)
常数(
执行节流阀=2
)
类型JobsManifest[]作业
类型作业结构{
cmd字符串
结果字符串
运行时int//模拟长时间运行的任务
}
func(j JobsManifest)queueJobs(logChan chan如果我没弄错的话,你的意思是建立一种机制,以确保在任何时候最多有多个EXEC\u THROTTLE
作业在运行。如果这是你的意图,那么代码就不起作用了
这是因为当你启动一个作业时,你已经消耗了通道-允许启动另一个作业,但没有完成任何作业。你可以通过添加一个计数器(你需要原子添加或互斥)来调试它
执行作业时,只需启动一组具有无缓冲通道和块的goroutine即可完成此工作:
func Run(j Job) r Result {
//Run your job here
}
func Dispatch(ch chan Job) {
for j:=range ch {
wg.Add(1)
Run(j)
wg.Done()
}
}
func main() {
ch := make(chan Job)
for i:=0; i<EXEC_THROTTLE; i++ {
go Dispatch(ch)
}
//call dispatch according to the queue here.
}
func运行(j作业)r结果{
//在这里管理你的工作
}
func调度(总陈工){
对于j:=范围ch{
工作组.添加(1)
运行(j)
wg.Done()
}
}
func main(){
ch:=制造(成龙工作)
对于i:=0;i如果我理解正确,您的意思是建立一种机制,以确保在任何时候最多有多个EXEC\u THROTTLE
作业正在运行。如果这是您的意图,则代码不起作用
这是因为当你启动一个作业时,你已经消耗了通道-允许启动另一个作业,但没有完成任何作业。你可以通过添加一个计数器(你需要原子添加或互斥)来调试它
执行作业时,只需启动一组具有无缓冲通道和块的goroutine即可完成此工作:
func Run(j Job) r Result {
//Run your job here
}
func Dispatch(ch chan Job) {
for j:=range ch {
wg.Add(1)
Run(j)
wg.Done()
}
}
func main() {
ch := make(chan Job)
for i:=0; i<EXEC_THROTTLE; i++ {
go Dispatch(ch)
}
//call dispatch according to the queue here.
}
func运行(j作业)r结果{
//在这里管理你的工作
}
func调度(总陈工){
对于j:=范围ch{
工作组.添加(1)
运行(j)
wg.Done()
}
}
func main(){
ch:=制造(成龙工作)
对于i:=0;i我经常使用它
我经常用这个
您还可以使用缓冲通道限制并发性:
concurrencyLimit := 2 // Number of simultaneous jobs.
limiter := make(chan struct{}, concurrencyLimit)
for job := range jobs {
job := job // Pin loop variable.
limiter <- struct{}{} // Reserve limiter slot.
go func() {
defer func() {
<-limiter // Free limiter slot.
}()
do(job) // Do the job.
}()
}
// Wait for goroutines to finish by filling full channel.
for i := 0; i < cap(limiter); i++ {
limiter <- struct{}{}
}
concurrentylimit:=2//同时作业的数量。
限制器:=make(chan结构{},并发限制)
对于作业:=范围作业{
作业:=作业//针循环变量。
限制器您还可以使用缓冲通道限制并发:
concurrencyLimit := 2 // Number of simultaneous jobs.
limiter := make(chan struct{}, concurrencyLimit)
for job := range jobs {
job := job // Pin loop variable.
limiter <- struct{}{} // Reserve limiter slot.
go func() {
defer func() {
<-limiter // Free limiter slot.
}()
do(job) // Do the job.
}()
}
// Wait for goroutines to finish by filling full channel.
for i := 0; i < cap(limiter); i++ {
limiter <- struct{}{}
}
concurrentylimit:=2//同时作业的数量。
限制器:=make(chan结构{},并发限制)
对于作业:=范围作业{
作业:=作业//针循环变量。
限制器将processItem函数替换为所需的作业执行
下面将按正确顺序执行作业。Atmost EXEC_并发项将同时执行
package main
import (
"fmt"
"sync"
"time"
)
func processItem(i int, done chan int, wg *sync.WaitGroup) {
fmt.Printf("Async Start: %d\n", i)
time.Sleep(100 * time.Millisecond * time.Duration(i))
fmt.Printf("Async Complete: %d\n", i)
done <- 1
wg.Done()
}
func popItemFromBufferChannelWhenItemDoneExecuting(items chan int, done chan int) {
_ = <- done
_ = <-items
}
func main() {
EXEC_CONCURRENT := 3
items := make(chan int, EXEC_CONCURRENT)
done := make(chan int)
var wg sync.WaitGroup
for i:= 1; i < 11; i++ {
items <- i
wg.Add(1)
go processItem(i, done, &wg)
go popItemFromBufferChannelWhenItemDoneExecuting(items, done)
}
wg.Wait()
}
package main
import (
"fmt"
"sync"
"time"
)
func processItem(i int, items chan int, wg *sync.WaitGroup) {
items <- i
fmt.Printf("Async Start: %d\n", i)
time.Sleep(100 * time.Millisecond * time.Duration(i))
fmt.Printf("Async Complete: %d\n", i)
_ = <- items
wg.Done()
}
func main() {
EXEC_CONCURRENT := 3
items := make(chan int, EXEC_CONCURRENT)
var wg sync.WaitGroup
for i:= 1; i < 11; i++ {
wg.Add(1)
go processItem(i, items, &wg)
}
wg.Wait()
}
主程序包
进口(
“fmt”
“同步”
“时间”
)
func processItem(i int,done chan int,wg*sync.WaitGroup){
fmt.Printf(“异步启动:%d\n”,i)
时间。睡眠(100*时间。毫秒*时间。持续时间(i))
fmt.Printf(“异步完成:%d\n”,i)
完成用所需的作业执行替换processItem函数
下面将按正确顺序执行作业。Atmost EXEC_并发项将同时执行
package main
import (
"fmt"
"sync"
"time"
)
func processItem(i int, done chan int, wg *sync.WaitGroup) {
fmt.Printf("Async Start: %d\n", i)
time.Sleep(100 * time.Millisecond * time.Duration(i))
fmt.Printf("Async Complete: %d\n", i)
done <- 1
wg.Done()
}
func popItemFromBufferChannelWhenItemDoneExecuting(items chan int, done chan int) {
_ = <- done
_ = <-items
}
func main() {
EXEC_CONCURRENT := 3
items := make(chan int, EXEC_CONCURRENT)
done := make(chan int)
var wg sync.WaitGroup
for i:= 1; i < 11; i++ {
items <- i
wg.Add(1)
go processItem(i, done, &wg)
go popItemFromBufferChannelWhenItemDoneExecuting(items, done)
}
wg.Wait()
}
package main
import (
"fmt"
"sync"
"time"
)
func processItem(i int, items chan int, wg *sync.WaitGroup) {
items <- i
fmt.Printf("Async Start: %d\n", i)
time.Sleep(100 * time.Millisecond * time.Duration(i))
fmt.Printf("Async Complete: %d\n", i)
_ = <- items
wg.Done()
}
func main() {
EXEC_CONCURRENT := 3
items := make(chan int, EXEC_CONCURRENT)
var wg sync.WaitGroup
for i:= 1; i < 11; i++ {
wg.Add(1)
go processItem(i, items, &wg)
}
wg.Wait()
}
主程序包
进口(
“fmt”
“同步”
“时间”
)
func processItem(i int,done chan int,wg*sync.WaitGroup){
fmt.Printf(“异步启动:%d\n”,i)
时间。睡眠(100*时间。毫秒*时间。持续时间(i))
fmt.Printf(“异步完成:%d\n”,i)
谢谢你的反馈@leadbebop,我会尝试建议并接受答案,一旦我整理好了。你可能会发现这篇博文很有帮助。嗨@leadbebop。也许我对你的评论感到困惑。
//根据这里的队列进行呼叫调度。
。我更新了队列以循环,直到EXEC\u THROTTLE
的长度,但正如你所说如果EXEC\u THROTTLE==2
,则只能看到前两个作业运行。我缺少什么?另外,我想我需要等待logger
返回调用wg.Done()
。你确实没有领会我的意思。我在这里更改了你的代码:首先通过我在答案中的解释来理解它。我发现很难解释更多,但如果还有什么不清楚的地方,请尽管问。谢谢。我以前觉得有必要在goroutine中调用run
,原因是我想阻止EXEC\u THROTTLE
,而不是每个作业
。经过编辑,似乎每个作业
都是按顺序运行的,而不是并行执行前两个,但现在通过研究您的答案,我意识到这是我的误解,因为它在运行
返回后立即发送到记录器Job
s的air具有与runtime
相同的值,很明显它是并行执行的。我真的很感谢你花时间来澄清这一点。感谢你的反馈@leadbebebop,我会尝试建议并接受答案,一旦我整理好了。你可能会发现这篇博客文章很有帮助。嗨@leadbebebop。也许我是conf用于你的通讯