golang代码实例库

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 3805|回复: 0

golang:使用信号量semaphore控制并发goroutine数量

[复制链接]

82

主题

82

帖子

486

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
486
发表于 2021-12-10 23:47:27 | 显示全部楼层 |阅读模式
实例说明
虽然在go中创建协程代价很小,但过多但协程也会对系统造成压力,甚至会将服务拖垮。
使用信号量semaphore,可以三行代码就控制并发执行goroutine的数量。

1)信号量semaphore控制协程数量
2)默认每一个协程申请一个信号量,如果协程有不同等级,比如有的处理任务重,则可以多申请几个信号量,则可以根据协程处理任务的轻重情况,动态控制协程的数量

实例代码
[Golang] 纯文本查看 复制代码
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
}


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|golang代码实例库 ( 粤ICP备2021162396号 )

GMT+8, 2025-2-8 11:19 , Processed in 0.018486 second(s), 20 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表