MST

星途 面试题库

面试题:Go context设计目的在并发控制方面的深入理解

在一个具有多个并发任务且相互依赖的Go程序中,如何利用context来实现任务的有序取消以及数据的安全传递,描述具体的设计思路和关键代码实现。
18.2万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 创建上下文:使用context.Background()作为根上下文,在此基础上衍生出带有取消功能的上下文ctx, cancel := context.WithCancel(context.Background())
  2. 传递上下文:将上下文传递给每个并发任务的函数,这样每个任务都可以感知到取消信号。
  3. 任务间依赖:利用通道(channel)来传递任务间的数据和依赖关系,确保数据安全传递。
  4. 有序取消:当需要取消任务时,调用cancel()函数,所有接收到该上下文的任务应在合适的时机检查上下文的取消信号并退出。

关键代码实现

package main

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

// 模拟一个有依赖的任务
func task1(ctx context.Context, ch chan int) {
    select {
    case <-ctx.Done():
        return
    case ch <- 1: // 向通道发送数据
        fmt.Println("Task1 completed and sent data")
    }
}

// 依赖task1结果的任务
func task2(ctx context.Context, ch1 chan int, ch2 chan int) {
    select {
    case <-ctx.Done():
        return
    case data := <-ch1:
        // 对task1的数据进行处理
        result := data * 2
        select {
        case <-ctx.Done():
            return
        case ch2 <- result:
            fmt.Println("Task2 completed and sent data")
        }
    }
}

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    ch1 := make(chan int)
    ch2 := make(chan int)

    go task1(ctx, ch1)
    go task2(ctx, ch1, ch2)

    // 主程序等待一段时间
    time.Sleep(2 * time.Second)

    // 取消任务
    cancel()

    // 关闭通道
    close(ch1)
    close(ch2)

    // 输出最终结果
    for result := range ch2 {
        fmt.Printf("Final result: %d\n", result)
    }
}

在上述代码中:

  • task1task2通过context.Context来感知取消信号。
  • task1task2之间通过通道ch1ch2传递数据,保证数据安全。
  • 主程序通过调用cancel()函数实现任务的有序取消,并通过关闭通道来确保资源释放和防止死锁。