技术文摘
Golang 函数中如何控制并发 goroutine 的数量
Golang 函数中如何控制并发 goroutine 的数量
在 Golang 开发中,利用 goroutine 进行并发编程能够显著提升程序的执行效率。然而,若不加控制地创建大量 goroutine,可能导致系统资源耗尽,程序性能下降甚至崩溃。学会在函数中控制并发 goroutine 的数量至关重要。
控制并发 goroutine 数量的常用方法之一是使用 sync.WaitGroup 和 sync.Mutex。sync.WaitGroup 用于等待一组 goroutine 完成,而 sync.Mutex 则用于同步访问共享资源。例如,假设有一个函数需要处理大量任务,我们可以限制同时运行的 goroutine 数量,避免资源过度消耗。
package main
import (
"fmt"
"sync"
)
func worker(id int, wg *sync.WaitGroup, mu *sync.Mutex, tasks chan int) {
defer wg.Done()
for task := range tasks {
mu.Lock()
fmt.Printf("Worker %d is processing task %d\n", id, task)
mu.Unlock()
}
}
func main() {
var wg sync.WaitGroup
var mu sync.Mutex
tasks := make(chan int, 100)
maxGoroutines := 5
for i := 0; i < maxGoroutines; i++ {
wg.Add(1)
go worker(i, &wg, &mu, tasks)
}
for i := 1; i <= 20; i++ {
tasks <- i
}
close(tasks)
wg.Wait()
}
在上述代码中,我们创建了一个固定数量的 goroutine 池,每个 goroutine 从 tasks 通道中获取任务并处理。通过 sync.WaitGroup 等待所有 goroutine 完成任务,sync.Mutex 则确保在打印任务信息时的线程安全。
另一种更简洁高效的方法是使用信号量模式,通过 sync.Semaphore 来限制并发数量。sync.Semaphore 是 Go 1.19 引入的新类型,用于控制对共享资源的并发访问数量。
package main
import (
"fmt"
"golang.org/x/sync/semaphore"
"sync"
)
func worker2(id int, sem *semaphore.Weighted, wg *sync.WaitGroup, tasks chan int) {
defer wg.Done()
for task := range tasks {
if err := sem.Acquire(nil, 1); err!= nil {
fmt.Printf("Worker %d acquire semaphore failed: %v\n", id, err)
return
}
fmt.Printf("Worker %d is processing task %d\n", id, task)
sem.Release(1)
}
}
func main2() {
var wg sync.WaitGroup
tasks := make(chan int, 100)
maxGoroutines := 5
sem := semaphore.NewWeighted(int64(maxGoroutines))
for i := 0; i < maxGoroutines; i++ {
wg.Add(1)
go worker2(i, sem, &wg, tasks)
}
for i := 1; i <= 20; i++ {
tasks <- i
}
close(tasks)
wg.Wait()
}
在实际项目中,根据具体需求选择合适的方法控制并发 goroutine 数量。通过合理控制并发度,能够充分利用系统资源,提升程序的性能和稳定性。
TAGS: 并发控制 Golang并发 Golang函数 goroutine数量