MST

星途 面试题库

面试题:Go Future模式下如何处理高并发任务的资源竞争与死锁问题

在使用Go的Future模式进行高并发编程时,常常会遇到资源竞争和死锁的风险。假设你正在开发一个系统,多个Future任务会访问和修改共享资源,请详细阐述你会采取哪些策略来避免资源竞争和死锁,例如使用sync包中的哪些工具,如何设计数据结构和算法来保证数据一致性,并给出相应的代码示例。
49.9万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 使用sync.Mutex避免资源竞争
    • sync.Mutex是Go语言中用于实现互斥锁的工具。当多个Future任务访问和修改共享资源时,通过在访问共享资源前后加锁和解锁,可以避免资源竞争。
    • 示例代码:
package main

import (
    "fmt"
    "sync"
)

var (
    sharedResource int
    mu             sync.Mutex
)

func futureTask(wg *sync.WaitGroup) {
    defer wg.Done()
    mu.Lock()
    sharedResource++
    mu.Unlock()
}

func main() {
    var wg sync.WaitGroup
    numTasks := 10
    for i := 0; i < numTasks; i++ {
        wg.Add(1)
        go futureTask(&wg)
    }
    wg.Wait()
    fmt.Println("Final value of shared resource:", sharedResource)
}
  1. 使用sync.RWMutex优化读操作
    • 如果共享资源读操作远多于写操作,可以使用sync.RWMutex。它允许多个读操作同时进行,但写操作时需要独占锁。
    • 示例代码:
package main

import (
    "fmt"
    "sync"
)

var (
    sharedData   int
    rwMutex      sync.RWMutex
)

func readTask(wg *sync.WaitGroup) {
    defer wg.Done()
    rwMutex.RLock()
    fmt.Println("Read value:", sharedData)
    rwMutex.RUnlock()
}

func writeTask(wg *sync.WaitGroup) {
    defer wg.Done()
    rwMutex.Lock()
    sharedData++
    rwMutex.Unlock()
}

func main() {
    var wg sync.WaitGroup
    numReadTasks := 5
    numWriteTasks := 3
    for i := 0; i < numReadTasks; i++ {
        wg.Add(1)
        go readTask(&wg)
    }
    for i := 0; i < numWriteTasks; i++ {
        wg.Add(1)
        go writeTask(&wg)
    }
    wg.Wait()
}
  1. 设计数据结构和算法保证数据一致性
    • 数据结构方面:可以将共享资源封装在一个结构体中,并将锁作为结构体的一个字段,这样可以更好地管理对共享资源的访问。
    • 算法方面:合理设计任务执行顺序,避免出现循环依赖导致死锁。例如,为每个任务分配一个唯一的ID,按照ID的顺序获取锁等。
    • 示例代码(封装共享资源和锁):
package main

import (
    "fmt"
    "sync"
)

type SharedResource struct {
    data int
    mu   sync.Mutex
}

func (sr *SharedResource) increment(wg *sync.WaitGroup) {
    defer wg.Done()
    sr.mu.Lock()
    sr.data++
    sr.mu.Unlock()
}

func main() {
    var wg sync.WaitGroup
    shared := SharedResource{}
    numTasks := 10
    for i := 0; i < numTasks; i++ {
        wg.Add(1)
        go shared.increment(&wg)
    }
    wg.Wait()
    fmt.Println("Final value of shared data:", shared.data)
}
  1. 使用sync.Cond避免死锁
    • sync.Cond用于在条件变量上等待或唤醒其他协程。当一个Future任务需要等待某个条件满足才能继续执行时,可以使用它。
    • 示例代码:
package main

import (
    "fmt"
    "sync"
    "time"
)

var (
    condition sync.Cond
    ready     bool
)

func task1(wg *sync.WaitGroup) {
    defer wg.Done()
    condition.L.Lock()
    for!ready {
        condition.Wait()
    }
    fmt.Println("Task 1 continues after condition is met")
    condition.L.Unlock()
}

func task2(wg *sync.WaitGroup) {
    defer wg.Done()
    time.Sleep(2 * time.Second)
    condition.L.Lock()
    ready = true
    condition.Broadcast()
    condition.L.Unlock()
}

func main() {
    var wg sync.WaitGroup
    var mu sync.Mutex
    condition = sync.Cond{L: &mu}
    wg.Add(2)
    go task1(&wg)
    go task2(&wg)
    wg.Wait()
}

通过这些策略,使用sync包中的工具,合理设计数据结构和算法,可以有效地避免在Go的Future模式高并发编程中出现资源竞争和死锁的问题。