MST

星途 面试题库

面试题:Go中context值传递在并发场景下的问题与解决方案

在一个包含多个并发goroutine的程序中,使用context传递上下文值。假设其中一个goroutine需要修改上下文中的值,并且其他goroutine要能及时获取到修改后的值,描述可能会遇到的问题以及如何解决,给出具体实现思路和关键代码片段。
23.8万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

可能遇到的问题

  1. 数据竞争:多个 goroutine 同时读写上下文的值,会导致数据竞争问题,使程序出现未定义行为。
  2. context 不可变特性:context 本身是不可变的,不能直接修改其值。

解决思路

  1. 使用共享变量并加锁:通过一个共享变量来存储需要修改的值,使用互斥锁(sync.Mutex)来保护对该变量的读写操作,确保同一时间只有一个 goroutine 能修改或读取该值。
  2. 使用 channel 通知:结合 channel 来通知其他 goroutine 值已发生变化,让其他 goroutine 主动从共享变量中获取最新值。

关键代码片段

package main

import (
    "context"
    "fmt"
    "sync"
)

type ContextValue struct {
    Value int
}

func main() {
    var mu sync.Mutex
    var sharedValue ContextValue
    valueChanged := make(chan struct{})

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

    // 模拟修改上下文值的 goroutine
    go func() {
        for {
            select {
            case <-ctx.Done():
                return
            default:
                mu.Lock()
                sharedValue.Value++
                mu.Unlock()
                valueChanged <- struct{}{}
            }
        }
    }()

    // 模拟获取上下文值的 goroutine
    go func() {
        for {
            select {
            case <-ctx.Done():
                return
            case <-valueChanged:
                mu.Lock()
                fmt.Println("New value:", sharedValue.Value)
                mu.Unlock()
            }
        }
    }()

    // 模拟程序运行一段时间
    select {}
}

在上述代码中:

  1. ContextValue 结构体用于表示上下文的值。
  2. mu 是一个互斥锁,用于保护对 sharedValue 的读写操作。
  3. valueChanged 是一个 channel,用于通知其他 goroutine 值已发生变化。
  4. 第一个 goroutine 定期修改 sharedValue,并通过 valueChanged channel 通知其他 goroutine。
  5. 第二个 goroutine 收到通知后,获取并打印最新的 sharedValue