Go 上下文对象 Context 如何关联 goroutine

27 min read

通常情况下,我们会在一个 goroutine 中创建一个上下文对象,然后将这个上下文对象传递给另一个或多个 goroutine 进行并发操作。这些 goroutine 可以在上下文对象的作用域内访问上下文对象中的属性,例如超时时间、取消函数等。这样,我们就可以通过上下文对象来控制 goroutine 的执行和停止。

下面是一个简单的示例,演示如何在多个 goroutine 中使用上下文对象:

package main

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

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
    defer cancel()

    ch := make(chan string)
    go worker(ctx, ch, "worker1")
    go worker(ctx, ch, "worker2")
    go worker(ctx, ch, "worker3")

    for {
        select {
        case <-ctx.Done():
            fmt.Println("main: context is done.")
            return
        case msg := <-ch:
            fmt.Println("main: received message:", msg)
        }
    }
}

func worker(ctx context.Context, ch chan<- string, name string) {
    for {
        select {
        case <-ctx.Done():
            fmt.Printf("%s: context is done.\n", name)
            return
        default:
            ch <- fmt.Sprintf("%s: hello", name)
            time.Sleep(1 * time.Second)
        }
    }
}

在上面的示例中,我们首先使用 context.WithTimeout() 函数创建了一个带超时的上下文对象 ctx,并设置超时时间为 3 秒。然后,我们创建了 3 个 goroutine,每个 goroutine 都执行 worker() 函数,其中传递了上下文对象 ctx 和一个带缓冲的字符串通道 ch

main() 函数中,我们使用 select 语句监听 ctx 上下文对象的取消信号和 ch 通道的消息。当 ctx 上下文对象被取消或超时时,select 语句会选择取消分支并退出程序;当 ch 通道有消息时,select 语句会选择接收分支并打印消息。

worker() 函数中,我们使用 select 语句监听 ctx 上下文对象的取消信号和默认分支。当 ctx 上下文对象被取消或超时时,select 语句会选择取消分支并返回;当默认分支被执行时,worker() 函数会向通道 ch 发送一条消息,然后睡眠 1 秒。

通过使用上下文对象 ctx,我们可以在多个 goroutine 中传递信息和控制并发操作。在这个示例中,我们通过上下文对象 ctx 实现了在超时时间内控制多个 goroutine 的执行和停止。