Go语言控制协程(goroutine)的并发数量,有哪些好的解决方法
Go语言圈
Go语言开发者的学习好助手,分享Go语言知识,技术技巧,学习与交流Go语言开发经验,互动才有助于技术的提升,每天5分钟,助你GO语言技术快乐成长
公众号
商务合作加微信: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语言的技术文章或视频教程,请关注本公众号获取并查看,感谢你的支持与信任!
学Go语言哪些事儿 · 目录
上一篇Go语言是如何防范 SQL注入、CSRF、XSS攻击 的下一篇Go语言 字符串拼接方式与性能比较,分析过没?
Go语言圈