golang优雅的结束协程

在 Go 语言里,协程(goroutine)本身没有内置的停止机制,不过可以借助一些技巧和工具来实现协程的停止,主要有三种方式。

1. 使用 context 包

context 包为在 Go 程序中传递请求范围的数据、取消信号和截止时间等提供了一种方式。可以利用 context 中的 WithCancel 函数创建一个可取消的上下文,进而实现协程的停止。
 
package main

import (
    "context"
    "fmt"
    "time"
)

func worker(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            fmt.Println("协程停止")
            return
        default:
            fmt.Println("协程正在工作...")
            time.Sleep(1 * time.Second)
        }
    }
}

func main() {
    ctx, cancel := context.WithCancel(context.Background())  // context.WithCancel 函数会创建一个可取消的上下文 ctx 以及一个取消函数 cancel
go worker(ctx)

    // 模拟一段时间后停止协程
    time.Sleep(5 * time.Second)
    cancel()

    // 等待一段时间,确保协程有机会停止
    time.Sleep(2 * time.Second)
}

2、使用通道

可以借助通道来向协程发送停止信号。示例如下:
 
package main

import (
    "fmt"
    "time"
)

func worker(stop chan bool) {
    for {
        select {
        case <-stop:
            fmt.Println("协程停止")
            return
        default:
            fmt.Println("协程正在工作...")
            time.Sleep(1 * time.Second)
        }
    }
}

func main() {
    stop := make(chan bool)
    go worker(stop)

    // 模拟一段时间后停止协程
    time.Sleep(5 * time.Second)
    stop <- true

    // 等待一段时间,确保协程有机会停止
    time.Sleep(2 * time.Second)
}

3. 利用共享变量

可以使用一个共享的布尔变量来控制协程的停止。示例如下:
 
package main

import (
    "fmt"
    "sync"
    "time"
)

var (
    stopFlag bool
    mu       sync.Mutex
)

func worker() {
    for {
        mu.Lock()
        if stopFlag {
            mu.Unlock()
            fmt.Println("协程停止")
            return
        }
        mu.Unlock()

        fmt.Println("协程正在工作...")
        time.Sleep(1 * time.Second)
    }
}

func main() {
    go worker()

    // 模拟一段时间后停止协程
    time.Sleep(5 * time.Second)

    mu.Lock()
    stopFlag = true
    mu.Unlock()

    // 等待一段时间,确保协程有机会停止
    time.Sleep(2 * time.Second)
}

 

posted @ 2025-05-04 23:46  zhjh256  阅读(7)  评论(0)    收藏  举报