在 Go 中,如果不注意一些细节,就可能会导致协程泄露。常见的协程泄露情况包括:
在协程中使用了全局变量:如果协程中使用了全局变量,而这个全局变量在程序运行过程中没有被及时清理,那么这个协程就会一直等待全局变量被清理,从而导致协程泄露。
package main
import (
"fmt"
"time"
)
var (
done chan bool = make(chan bool)
)
func main() {
go func() {
for {
select {
case <-done:
fmt.Println("goroutine is done")
return
default:
// 协程一直在等待 done 变量被关闭
fmt.Println("goroutine is running")
time.Sleep(100 * time.Millisecond)
}
}
}()
time.Sleep(1 * time.Second)
// 没有关闭 done 变量,导致协程泄露
}
在这个示例代码中,我们创建了一个全局的 done 变量,并在一个协程中使用它进行等待。如果在程序运行过程中没有及时关闭 done 变量,那么这个协程就会一直等待下去,从而导致协程泄露。
协程阻塞:如果一个协程在运行过程中一直阻塞,而没有其他协程来唤醒它,那么这个协程就会一直占用系统资源,从而导致协程泄露。
package main
import (
"fmt"
"time"
)
func main() {
go func() {
// 协程一直在等待通道写入数据,而主 goroutine 没有向通道写入数据
<-make(chan bool)
}()
time.Sleep(1 * time.Second)
// 没有向通道写入数据,导致协程泄露
}
在这个示例代码中,我们创建了一个协程并在其中使用通道进行阻塞等待。如果在程序运行过程中没有其他协程向通道写入数据,那么这个协程就会一直阻塞等待下去,从而导致协程泄露。
为避免协程泄露,需要注意及时清理协程使用的资源,以及避免协程的阻塞。在实际编程中,可以使用 sync.WaitGroup 来协调协程的启动和结束,从而避免协程泄露。