Go 项目中的 Goroutine 泄露及其防范措施
package main
import (
"fmt"
"runtime"
"runtime/debug"
"time"
)
func main() {
// 设置最大线程数,防止因为goroutine过多导致的系统资源耗尽
runtime.GOMAXPROCS(1)
// 使用一个channel来控制并发的goroutine数量
sem := make(chan bool, 3)
// 记录goroutine的数量
var goroutines int
// 创建一个goroutine来定期打印当前的goroutine数量
go func() {
for {
time.Sleep(time.Second)
n := runtime.NumGoroutine()
if n != goroutines {
fmt.Printf("当前goroutine数量: %d\n", n)
goroutines = n
}
}
}()
// 创建一些模拟任务
tasks := []string{"任务1", "任务2", "任务3", "任务4", "任务5"}
for _, task := range tasks {
task := task // 为了闭包
sem <- true // 等待前面的 goroutine 完成
go func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf("任务 '%s' 发生了 panic: %v\n", task, r)
debug.PrintStack()
}
<-sem // 任务完成
}()
// 这里模拟任务执行
fmt.Printf("开始执行任务: %s\n", task)
time.Sleep(time.Second)
fmt.Printf("任务: %s 执行完成\n", task)
}()
}
// 等待所有任务完成
for i := 0; i < cap(sem); i++ {
sem <- true
}
// 程序退出前再次打印goroutine数量
fmt.Printf("所有任务完成,最终goroutine数量: %d\n", runtime.NumGoroutine())
}
这段代码首先设置了Go程序使用的最大线程数,以防止因为goroutine过多导致的系统资源耗尽。然后,它使用一个channel来控制并发的goroutine数量,以防止同时执行太多任务而引起的资源问题。代码中使用了runtime.NumGoroutine()
来记录当前的goroutine数量,并且定时打印出来。此外,每个goroutine中都使用了recover
机制来防止程序因为goroutine中的错误而崩溃。最后,代码等待所有任务完成后,再次打印当前的goroutine数量,并安全地退出程序。
评论已关闭