MST

星途 面试题库

面试题:Gochannel的同步与数据竞争

假设你有多个goroutine通过Gochannel进行数据传递,如何确保在并发环境下数据的一致性和避免数据竞争问题?请阐述具体的原理和可能用到的同步机制,并编写一段示例代码展示如何解决这个问题。
39.6万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 原理
    • Go语言中通过channel进行数据传递本身就提供了一种同步机制。channel是类型化的管道,在多个goroutine之间传递数据时,发送操作(<-左边)和接收操作(<-右边)是同步的。当一个goroutine向channel发送数据时,它会阻塞,直到另一个goroutine从该channel接收数据;反之,当一个goroutine从channel接收数据时,它也会阻塞,直到有数据被发送到该channel。这就避免了多个goroutine同时访问和修改同一数据的情况,从而保证了数据的一致性。
    • 除了channel,Go还提供了sync包中的一些同步原语,如Mutex(互斥锁)、WaitGroup等,也可以用于解决数据竞争问题。Mutex用于保护共享资源,保证同一时间只有一个goroutine可以访问共享资源;WaitGroup用于等待一组goroutine完成任务。
  2. 可能用到的同步机制
    • channel:作为Go语言并发编程的核心机制,用于在goroutine之间安全地传递数据。
    • Mutex:互斥锁,用于保护共享资源,防止多个goroutine同时访问。
    • WaitGroup:用于等待一组goroutine完成工作,确保在所有相关goroutine完成操作后再进行后续处理。
  3. 示例代码
package main

import (
    "fmt"
    "sync"
)

// 定义一个结构体来表示共享数据
type SharedData struct {
    value int
    mu    sync.Mutex
}

// 函数用于修改共享数据
func modifyData(data *SharedData, wg *sync.WaitGroup, ch chan struct{}) {
    defer wg.Done()
    // 使用channel来同步开始修改操作
    <-ch
    data.mu.Lock()
    data.value++
    data.mu.Unlock()
}

func main() {
    var wg sync.WaitGroup
    sharedData := SharedData{value: 0}
    ch := make(chan struct{})

    // 启动多个goroutine
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go modifyData(&sharedData, &wg, ch)
    }

    // 发送信号给所有goroutine开始执行
    for i := 0; i < 5; i++ {
        ch <- struct{}{}
    }
    close(ch)

    // 等待所有goroutine完成
    wg.Wait()

    fmt.Println("Final value:", sharedData.value)
}

在这个示例中:

  • 我们定义了一个SharedData结构体,其中包含一个共享的整数值value和一个Mutex来保护这个值。
  • modifyData函数是一个goroutine执行的函数,它通过从channel接收信号来开始操作,使用Mutex锁定共享数据,修改数据后解锁。
  • main函数中,我们创建了一个WaitGroup来等待所有goroutine完成,一个channel来同步启动所有goroutine的修改操作。启动5个goroutine,然后通过channel发送信号让它们开始工作,最后等待所有goroutine完成并打印最终的共享数据值。这样就确保了在并发环境下数据的一致性并避免了数据竞争问题。