在 go 中使用 context.WithTimeout 重用父上下文?

Isa*_*iah 4 go

使用 context.WithTimeout 重用父上下文和新的超时

你好,我是新来的go。我想知道是否可以重用父上下文来创建多个 context.withTimeout()。基本原理是我必须按顺序调用多个网络请求,并希望使用父级的上下文同时为每个请求设置超时。

基本原理

当父的上下文被取消时,所有发出的请求也将被取消。

问题

在下面的代码中,它显示了一个示例,LongProcess即网络请求。但是,在LongProcess可以使用 a 进行第二次调用之前,上下文已关闭context deadline exceeded

该文件withDeadline指出The returned context's Done channel is closed when the deadline expires, when the returned cancel function is called, or when the parent context's Done channel isclosed, whichever happens first.

因此,如果是这种情况,有没有办法可以重置 withTimeout 的计时器?还是我必须context.Background()为每个请求创建一个新的上下文?这意味着不会传递父上下文。:(


// LongProcess refers to a long network request
func LongProcess(ctx context.Context, duration time.Duration, msg string) error {
    c1 := make(chan string, 1)
    go func() {
        // Simulate processing
        time.Sleep(duration)
        c1 <- msg
    }()

    select {
    case m := <-c1:
        fmt.Println(m)
        return nil
    case <-ctx.Done():
        return ctx.Err()
    }
}

func main() {
    ctx := context.Background()
    t := 2 * time.Second

    ctx, cancel := context.WithTimeout(ctx, t)
    defer cancel()

    // Simulate a 2 second process time
    err := LongProcess(ctx, 2*time.Second, "first process")
    fmt.Println(err)

    // Reusing the context.
    s, cancel := context.WithTimeout(ctx, t)
    defer cancel()

    // Simulate a 1 second process time
    err = LongProcess(s, 1*time.Second, "second process")
    fmt.Println(err) // context deadline exceeded
}

Run Code Online (Sandbox Code Playgroud)

Sam*_*ant 5

看起来像是第一次调用context.WithTimeout隐藏父上下文ctx。后面的过程重新使用这个已经取消的上下文,因此出现错误。您必须重新使用父项。这是更新的示例:

func main() {
    // Avoid to shadow child contexts
    parent := context.Background()
    t := 2 * time.Second

    // Use the parent context.
    ctx1, cancel := context.WithTimeout(parent, t)
    defer cancel()

    err := LongProcess(ctx1, 2*time.Second, "first process")
    fmt.Println(err)

    // Use the parent context not the canceled one.
    ctx2, cancel := context.WithTimeout(parent, t)
    defer cancel()

    err = LongProcess(ctx2, 1*time.Second, "second process")
    fmt.Println(err)
}
Run Code Online (Sandbox Code Playgroud)