go中的context超时控制、超时传递、跨进程超时传递

发布于:2024-03-29 ⋅ 阅读:(23) ⋅ 点赞:(0)

context包中的WithCancel、WithDeadline和WithTimeout函数提供了创建上下文(context)对象的能力,这些上下文对象对于管理goroutine的生命周期非常重要,尤其是在处理取消、超时和截止时间的场景中。

  1. WithCancel
    WithCancel函数返回一个新的上下文对象和一个取消函数。调用这个取消函数将取消这个上下文对象,以及从它派生的所有上下文对象。

作用与意义
WithCancel用于创建可以被手动取消的上下文。这对于告知goroutine停止当前工作并及时退出非常有用。

代码案例

package main

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

func operation(ctx context.Context, duration time.Duration) {
    select {
    case <-time.After(duration):
        fmt.Println("Operation finished")
    case <-ctx.Done():
        fmt.Println("Operation cancelled")
    }
}

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    go operation(ctx, 5*time.Second)

    time.Sleep(2 * time.Second) // 模拟在操作完成前进行取消
    cancel() // 取消操作

    // 等待足够长的时间以确保goroutine可以响应取消事件
    time.Sleep(1 * time.Second)
}
  1. WithDeadline
    WithDeadline函数返回一个新的上下文对象,这个对象会在指定的截止时间自动取消。

作用与意义
WithDeadline用于创建具有明确截止时间的上下文。当达到截止时间时,上下文会自动取消。这对于设置任务的最长执行时间非常有用。

代码案例

package main

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

func main() {
    deadline := time.Now().Add(3 * time.Second)
    ctx, cancel := context.WithDeadline(context.Background(), deadline)
    defer cancel()

    select {
    case <-time.After(5 * time.Second):
        fmt.Println("Operation finished")
    case <-ctx.Done():
        fmt.Println("Operation cancelled due to deadline")
    }
}
  1. WithTimeout
    WithTimeout函数是WithDeadline的便捷版本,它返回一个新的上下文对象,这个对象会在指定的超时时间后自动取消。

作用与意义
WithTimeout用于创建具有超时限制的上下文。当超过超时时间时,上下文会自动取消。这适用于需要限制执行时间的任务。

代码案例

package main

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

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

    select {
    case <-time.After(5 * time.Second):
        fmt.Println("Operation finished")
    case <-ctx.Done():
        fmt.Println("Operation cancelled due to timeout")
    }
}

总结
WithCancel、WithDeadline和WithTimeout是context包中非常重要的函数,它们允许开发者基于取消信号、截止时间和超时控制goroutine的行为。使用这些机制可以让并发程序更加健壮,更容易管理资源和控制goroutine的生命周期。

超时传递
超时传递指的是当一个操作有多个步骤或依赖多个服务时,整个操作的超时设置可以从顶层传递到每个子操作。这样做可以确保整个操作链在给定的超时时间内完成,避免某个子操作耗时过长影响整体性能。

超时传递的代码案例
假设我们有一个任务,它需要依次执行两个步骤,每个步骤都可能耗时,我们希望整个任务在规定的超时时间内完成。

package main

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

func step1(ctx context.Context) error {
    // 模拟耗时的操作
    select {
    case <-ctx.Done():
        return ctx.Err()
    case <-time.After(1 * time.Second):
        fmt.Println("Step 1 completed")
        return nil
    }
}

func step2(ctx context.Context) error {
    // 模拟耗时的操作
    select {
    case <-ctx.Done():
        return ctx.Err()
    case <-time.After(2 * time.Second):
        fmt.Println("Step 2 completed")
        return nil
    }
}

func task(ctx context.Context) {
    // 执行第一步
    if err := step1(ctx); err != nil {
        fmt.Println("Task failed:", err)
        return
    }
    // 执行第二步
    if err := step2(ctx); err != nil {
        fmt.Println("Task failed:", err)
        return
    }
    fmt.Println("Task completed successfully")
}

func main() {
    // 创建一个总超时时间为3秒的上下文
    ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
    defer cancel()

    task(ctx)
}

在这个例子中,我们有两个步骤(step1和step2),它们都接受一个上下文对象ctx。这个上下文对象是通过WithTimeout创建的,意味着整个任务有一个总的超时时间限制。每个步骤在执行时都会检查这个上下文对象,以确定是否已经超时或被取消。如果在任一步骤中超时发生,任务将提前终止并报告失败。这个模式确保了超时可以从任务的顶层传递到每个子操作中,使得整个操作链能够响应超时事件。

本文含有隐藏内容,请 开通VIP 后查看