Go语言控制协程(goroutine)的并发数量,有哪些好的解决方法
Go语言控制协程(goroutine)的并发数量,有哪些好的解决方法
商务合作加微信:LetsFeng
现在就开始你的Go语言学习之旅吧!人生苦短,let’s Go.
Goland 全家桶激活码,免费获取了,赶紧下手
https://web.52shizhan.cn
在使用协程并发处理某些任务时, 其并发数量往往因为各种因素的限制不能无限的增大. 例如网络请求、数据库查询等等。
从运行效率角度考虑,在相关服务可以负载的前提下(限制最大并发数),尽可能高的并发。
在Go语言中,可以使用一些方法来控制协程(goroutine)的并发数量,以防止并发过多导致资源耗尽或性能下降。以下是一些常见的方法:
1. 使用信号量(Semaphore):
可以使用 Go 语言中的 channel 来实现简单的信号量,限制并发数量。
package main
import (
"fmt"
"sync"
)
func worker(id int, sem chan struct{}) {
sem <- struct{}{} // 占用一个信号量
defer func() {
<-sem // 释放信号量
}()
// 执行工作任务
fmt.Printf("Worker %d: Working...\n", id)
}
func main() {
concurrency := 3
sem := make(chan struct{}, concurrency)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
worker(id, sem)
}(i)
}
wg.Wait()
close(sem)
}
在上述例子中,sem
是一个有缓冲的 channel,通过控制 channel 中元素的数量,实现了一个简单的信号量机制。
2. 使用协程池:
可以创建一个固定数量的协程池,将任务分发给这些协程执行。
package main
import (
"fmt"
"sync"
)
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Printf("Worker %d: Working on job %d\n", id, j)
results <- j * 2
}
}
func main() {
const numJobs = 5
const numWorkers = 3
jobs := make(chan int, numJobs)
results := make(chan int, numJobs)
var wg sync.WaitGroup
// 启动协程池
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
worker(id, jobs, results)
}(i)
}
// 提交任务
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs)
// 等待所有工作完成
go func() {
wg.Wait()
close(results)
}()
// 处理结果
for result := range results {
fmt.Println("Result:", result)
}
}
在上述例子中,jobs
通道用于存储任务,results
通道用于存储处理结果。通过创建固定数量的工作协程,可以有效地控制并发数量。
3. 使用 `golang.org/x/sync/semaphore` 包:
Go 1.16 引入了 golang.org/x/sync/semaphore
包,它提供了一个更为灵活的信号量实现。
package main
import (
"fmt"
"golang.org/x/sync/semaphore"
"sync"
)
func worker(id int, sem *semaphore.Weighted) {
sem.Acquire(semaphore.WithWeight(1))
defer sem.Release(1)
// 执行工作任务
fmt.Printf("Worker %d: Working...\n", id)
}
func main() {
concurrency := 3
sem := semaphore.NewWeighted(int64(concurrency))
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
worker(id, sem)
}(i)
}
wg.Wait()
}
在上述例子中,使用 golang.org/x/sync/semaphore
包创建了一个带权重的信号量,控制协程的并发数量。
选择哪种方法取决于具体的应用场景和需求。使用信号量是一种简单而灵活的方法,而协程池则更适用于需要批量处理任务的情况。golang.org/x/sync/semaphore
包提供了一个标准库外的更灵活的信号量实现。
文章首发:
更多相关Go语言的技术文章或视频教程,请关注本公众号获取并查看,感谢你的支持与信任!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)
2022-01-07 golang Gorm 运用及执行原生SQL
2022-01-07 Redis集群到集群迁移
2022-01-07 关于gorm多表联合查询(left join)
2022-01-07 Gin gorm
2021-01-07 解决问题:mysql 1040 too many connections
2019-01-07 Prometheus+AlertManager实现邮件报警