在Go
语言中,Goroutine
是一种轻量级线程,它的退出机制对于并发编程至关重要。
函数或方法执行完毕
最常见的Goroutine
退出方式是函数或方法执行完毕。当Goroutine
中的函数或方法执行完毕时,该Goroutine
会自动退出。
package main
import (
"fmt"
"time"
)
func main() {
go func() {
// Goroutine 中的函数执行完毕后自动退出
fmt.Println("Goroutine execution complete")
}()
// 主 Goroutine 继续执行其他任务
time.Sleep(time.Second)
fmt.Println("Main Goroutine execution complete")
}
在上面的示例中,我们创建了一个匿名的Goroutine
,在其中打印一条消息,然后Goroutine
执行完毕并自动退出。主Goroutine
继续执行其他任务。
子协程返回
在Goroutine
中,我们可以使用return
语句显式地退出。当执行到return
语句时,该Goroutine
将会终止并返回,注:协程是没有返回值的,如果要返回,一般是用chan,往chan中写入,外部一般用waitgroup等待go执行完成后,读取chan的结果。
package main
import (
"fmt"
"time"
)
func main() {
go func() {
// Goroutine 中使用 return 语句显式退出
fmt.Println("Goroutine execution")
return
}()
// 主 Goroutine 继续执行其他任务
time.Sleep(time.Second)
fmt.Println("Main Goroutine execution complete")
}
在上面的示例中,我们创建了一个匿名的Goroutine
,并在其中打印一条消息,然后使用return
语句显式地退出Goroutine
,这里演示的是函数末尾return
,实际工作中很可能是中途需要return
。
panic()与recover()
如果在Goroutine
中发生了panic
,默认情况下会终止当前程序的执行。我们可以在Goroutine
中使用recover()
函数来捕获并处理panic
,以避免程序崩溃。
package main
import (
"fmt"
"time"
)
func main() {
go func() {
defer func() {
if err := recover(); err != nil {
// 在 Goroutine 中捕获并处理panic
fmt.Println("Recovered from panic:", err)
}
}()
// 引发恐慌
panic("Goroutine panic")
}()
// 主 Goroutine 继续执行其他任务
time.Sleep(time.Second)
fmt.Println("Main Goroutine execution complete")
}
在上面的示例中,我们创建了一个匿名的Goroutine
,在其中使用panic()
引发panic
。然后使用defer
和recover()
捕获并处理panic
,确保程序不会崩溃。
context的取消
Go
语言的context
包提供了一种机制来管理Goroutine
的生命周期,包括取消正在运行的Goroutine
。我们可以使用context.Context
的cancel()
方法来取消Goroutine
的执行。一旦Goroutine
接收到取消信号,它应该尽快退出。
package main
import (
"context"
"fmt"
"time"
)
func worker(ctx context.Context) {
for {
select {
case <-ctx.Done():
// 接收到取消信号后退出 Goroutine
fmt.Println("Goroutine execution canceled")
return
default:
// 执行正常任务
fmt.Println("Goroutine executing...")
time.Sleep(time.Second)
}
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
go worker(ctx)
// 模拟取消任务
time.Sleep(3 * time.Second)
cancel()
// 主 Goroutine 继续执行其他任务
time.Sleep(time.Second)
fmt.Println("Main Goroutine execution complete")
}
在上面的示例中,我们创建了一个worker
函数,在其中使用select
和ctx.Done()
判断是否接收到取消信号。当取消信号到达时,Goroutine
会及时退出。