为了避免 goroutine 泄漏,go 框架提供了以下机制:使用上下文(context)取消未使用的 goroutine;使用 goroutine 组跟踪 goroutine 并通知完成;使用管道发送取消信号。实战案例中,上下文用于在取消时退出 goroutine,goroutine 组用于跟踪 goroutine 的完成,管道用于发送取消信号。
避免 Golang 框架中 Goroutine 泄漏的技巧
Goroutine 泄漏是一个常见的 Go 应用程序问题,它会导致内存浪费和性能下降。为了避免这种情况,Golang 框架提供了多种机制:
1. 使用上下文(Context)
立即学习“go语言免费学习笔记(深入)”;
上下文可以用来取消未使用的 Goroutine。使用 context.WithCancel() 创建一个新的上下文,并传递给 Goroutine 函数:
ctx, cancel := context.WithCancel(context.Background()) go func() { for { select { case <-ctx.Done(): return default: // 执行 Goroutine 任务 } } }() // ... cancel() // 取消 Goroutine
2. 使用 Goroutine 组
Goroutine 组可以跟踪一组 Goroutine,并在它们全部完成时通知。使用 sync.WaitGroup 创建一个新的 Goroutine 组,并传递给 Goroutine 函数:
var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { // 执行 Goroutine 任务 wg.Done() }() } // ... wg.Wait() // 等待所有 Goroutine 完成
3. 使用管道(Channel)
管道可以用来向 Goroutine 发送一个取消信号,关闭管道将通知 Goroutine 退出:
done := make(chan struct{}) go func() { for { select { case <-done: return default: // 执行 Goroutine 任务 } } }() // ... close(done) // 发送取消信号
实战案例
示例 1: 使用上下文
package main import ( "context" "fmt" "sync" "time" ) func main() { ctx, cancel := context.WithCancel(context.Background()) var wg sync.WaitGroup wg.Add(1) go longRunningGoroutine(ctx, &wg) time.Sleep(5 * time.Second) cancel() wg.Wait() } func longRunningGoroutine(ctx context.Context, wg *sync.WaitGroup) { defer wg.Done() for { select { case <-ctx.Done(): fmt.Println("Goroutine has been cancelled") return default: fmt.Println("Goroutine is running") time.Sleep(1 * time.Second) } } }
在上面的示例中,longRunningGoroutine() 在一个单独的 Goroutine 中运行,它每秒向控制台打印Goroutine is running。当用户按下任意键时,主 Goroutine 取消上下文的上下文的Done()通道,这会通知longRunningGoroutine() 退出。
示例 2: 使用 Goroutine 组
package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func(i int) { fmt.Println("Goroutine", i) wg.Done() }(i) } wg.Wait() }
在上面的示例中,主 Goroutine 使用一个 Goroutine 组来跟踪 10 个 Goroutine。每个 Goroutine打印其 ID,然后通知 Goroutine 组它已完成。主 Goroutine等待所有 Goroutine 完成,然后退出。
示例 3: 使用管道
package main import ( "fmt" "sync" "time" ) func main() { done := make(chan struct{}) var wg sync.WaitGroup wg.Add(1) go longRunningGoroutine(done, &wg) time.Sleep(5 * time.Second) close(done) wg.Wait() } func longRunningGoroutine(done <-chan struct{}, wg *sync.WaitGroup) { defer wg.Done() for { select { case <-done: fmt.Println("Goroutine has been cancelled") return default: fmt.Println("Goroutine is running") time.Sleep(1 * time.Second) } } }
在上面的示例中,longRunningGoroutine() 在一个单独的 Goroutine 中运行,它每秒向控制台打印Goroutine is running。当用户按下任意键时,主 Goroutine 关闭done通道,这将通知longRunningGoroutine() 退出。
本站部分资源来源于网络,仅限用于学习和研究目的,请勿用于其他用途。
如有侵权请发送邮件至1943759704@qq.com删除
码农资源网 » golang框架如何避免 Goroutine 泄漏?