MST

星途 面试题库

面试题:Go中多个子协程共享Context的超时处理

假设你有一个主函数启动了多个子协程,并且这些子协程共享同一个`context.Context`来实现超时控制。当其中一个子协程完成任务后,如何优雅地通知其他子协程停止工作以避免不必要的资源消耗,同时保证超时机制仍然正常工作?请给出思路和关键代码片段。
47.9万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

思路

  1. 利用context.Context的取消功能context.Context 本身具有取消功能,我们可以在一个子协程完成任务时,调用取消函数来通知其他子协程。
  2. 在子协程中监听取消信号:每个子协程在执行任务的过程中,需要不断检查 context.Context 是否被取消。一旦检测到取消信号,就停止当前的工作,并清理相关资源。

关键代码片段(以Go语言为例)

package main

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

func worker(ctx context.Context, id int) {
    for {
        select {
        case <-ctx.Done():
            fmt.Printf("Worker %d received cancel signal, stopping...\n", id)
            return
        default:
            // 模拟工作
            fmt.Printf("Worker %d is working...\n", id)
            time.Sleep(100 * time.Millisecond)
        }
    }
}

func main() {
    // 创建带有超时的context
    ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
    defer cancel()

    // 启动多个子协程
    for i := 1; i <= 3; i++ {
        go worker(ctx, i)
    }

    // 模拟某个子协程提前完成任务
    go func() {
        time.Sleep(200 * time.Millisecond)
        fmt.Println("One worker finished, canceling others...")
        cancel()
    }()

    // 等待一段时间,确保所有子协程有机会处理取消信号
    time.Sleep(300 * time.Millisecond)
}

在上述代码中:

  1. worker 函数代表子协程,通过 select 语句监听 ctx.Done() 通道来检测是否收到取消信号。
  2. main 函数中,首先创建了一个带有超时的 context,然后启动多个 worker 子协程。
  3. 模拟某个子协程提前完成任务,调用 cancel 函数,这会向所有子协程的 ctx.Done() 通道发送信号,从而通知它们停止工作。同时,原有的超时机制依然生效,如果在超时时间内没有手动调用 cancelcontext 也会自动取消。