golang:使用信号量semaphore控制并发goroutine数量
■实例说明虽然在go中创建协程代价很小,但过多但协程也会对系统造成压力,甚至会将服务拖垮。
使用信号量semaphore,可以三行代码就控制并发执行goroutine的数量。
1)信号量semaphore控制协程数量
2)默认每一个协程申请一个信号量,如果协程有不同等级,比如有的处理任务重,则可以多申请几个信号量,则可以根据协程处理任务的轻重情况,动态控制协程的数量
■实例代码
package main
import (
"context"
"fmt"
"sync"
"time"
"golang.org/x/sync/semaphore"
)
// ControlGoRoutineCount 使用指定数量的协程处理某项工作
func ControlGoRoutineCount(goroutineCount int64) {
weight := int64(1)
// 创建信号量,一共只有goroutineCount个信号量可以申请,申请到了继续执行,申请不到需要等待
sem := semaphore.NewWeighted(goroutineCount)
wc := sync.WaitGroup{}
// 这里比如需要执行1000次某个任务,我们是用goroutine去执行
// 我们可以根据实际情况,替换这里的提交
for t := 0; t < 1000; t++ {
wc.Add(1)
// 检查是否还有信号量,只有有的话才会继续创建协程,否则会在这里等待,直到有信号量被释放
// 这里是申请1个信号量,如果这个任务重,可以根据实际情况申请多个信号量,相当于这里一个协程相当于其他几个协程
sem.Acquire(context.Background(), weight)
go func() {
defer func() {
wc.Done()
// 任务完成了,释放1个信号量
// 申请几个,释放几个
sem.Release(weight)
}()
// 这里执行自己的任务
// 这里使用sleep代替具体执行任务
time.Sleep(1 * time.Second)
}()
}
wc.Wait()
}
// NoControlGoRoutineCount 不控制进程数量,直接使用协程处理任务
func NoControlGoRoutineCount() {
wc := sync.WaitGroup{}
for t := 0; t < 1000; t++ {
wc.Add(1)
go func() {
defer func() {
wc.Done()
}()
// 这里执行自己的任务
// 这里使用sleep代替具体执行任务
time.Sleep(1 * time.Second)
}()
}
wc.Wait()
}
func main() {
// 第一个方法控制只有200个协程可以执行,第二个方法不受控制,直接循环1000次,相当于有1000个协程同时执行
// 所以控制协程数量的比不控制的慢了5倍的时间
curTime := time.Now()
// 控制只有100个协程处理某项工作
ControlGoRoutineCount(200)
fmt.Printf("ControlGoRoutineCount cost %d\n", time.Since(curTime))
// 输出:ControlGoRoutineCount cost 5018998668
curTime = time.Now()
// 不控制协程数量,直接处理某项工作
NoControlGoRoutineCount()
fmt.Printf("NoControlGoRoutineCount cost %d\n", time.Since(curTime))
// 输出:NoControlGoRoutineCount cost 1004587808
}
页:
[1]