关闭协程是go开发中一个重要而又容易被忽视的问题,一个未关闭的协程会一直占据系统资源,直到程序退出。优雅关闭协程是保证Go语言高效运行的一个关键因素。下面是一些优雅关闭协程的方法:
方法1:使用 context
go 1.7版本中引入了context包,该包提供了一种可用于不同goroutine间传递上下文信息的策略。我们通过WithCancel方法实现优雅关闭协程:
package main
import (
"context"
"fmt"
"time"
)
func work(ctx context.Context) {
for {
select {
default:
fmt.Println("working...")
time.Sleep(time.Second)
case <-ctx.Done():
fmt.Println("stop working")
return
}
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
go work(ctx)
time.Sleep(3 * time.Second)
cancel()
time.Sleep(time.Second)
fmt.Println("main end")
}
在work()函数中,我们使用了一个for循环和一个select,循环执行工作并通过select阻塞直至收到ctx.Done()信号。在main()函数中,我们使用context.Background()创建了上下文,并通过context.WithCancel()返回一个新的上下文ctx和一个函数cancel,用于优雅地停止协程。
通常情况下,我们先延迟stopChan信号,直至收到了停止信号才关闭这个信号,这样可以等待协程结束清理资源,如示例所示。
方法2:使用 channel
另一种可行的方法是使用一个信号channel,此时需要协程本身或其他协程向信号channel发送关闭信号,以请求协程停止运行。示例如下:
package main
import (
"fmt"
"time"
)
func work(stopChan chan struct{}) {
for {
select {
default:
fmt.Println("working...")
time.Sleep(time.Second)
case <-stopChan:
fmt.Println("stop working")
return
}
}
}
func main() {
stopChan := make(chan struct{})
go work(stopChan)
time.Sleep(3 * time.Second)
close(stopChan)
time.Sleep(time.Second)
fmt.Println("main end")
}
在work()函数中,我们使用了一个for循环和一个select,循环执行工作并通过select阻塞直至收到stopChan信号。在main()函数中,我们创建了一个信号channel,并通过close()函数发送停止信号给work()函数。
需要注意的是,在使用channel进行优雅关闭时,需要使用struct{}类型,因为它是一个零大小数据类型,不会占用过多内存空间。
综上所述,通过使用context或channel对go协程进行优雅关闭是十分重要的,可以避免程序因协程泄漏而导致不必要的内存和资源浪费。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:go语言开发中如何优雅得关闭协程方法 - Python技术站