MST

星途 面试题库

面试题:Go chan非阻塞操作中的数据竞争问题

在Go语言使用chan进行非阻塞操作时,可能会出现数据竞争的情况。请分析产生数据竞争的原因,并说明如何通过代码示例来避免这种情况。
38.3万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

数据竞争产生原因

  1. 多个goroutine并发访问:当多个goroutine同时尝试对共享资源(这里指通过chan进行数据交互相关的共享状态,比如chan的缓冲区状态等)进行读写操作时,如果没有适当的同步机制,就可能出现数据竞争。
  2. 非阻塞操作特性:在非阻塞操作中,由于操作不会等待,多个goroutine可能会在同一时间点尝试读写chan相关状态,例如在使用select语句进行非阻塞的sendreceive操作时,不同goroutine的select分支可能会同时触发,导致对chan的并发访问冲突。

避免数据竞争的代码示例

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    ch := make(chan int)

    // 生产者
    wg.Add(1)
    go func() {
        defer wg.Done()
        for i := 0; i < 5; i++ {
            select {
            case ch <- i:
            default:
                fmt.Println("Producer: Channel is full, skipping", i)
            }
        }
        close(ch)
    }()

    // 消费者
    wg.Add(1)
    go func() {
        defer wg.Done()
        for val := range ch {
            fmt.Println("Consumer:", val)
        }
    }()

    wg.Wait()
}

在上述代码中:

  1. 同步机制:使用sync.WaitGroup来确保所有goroutine完成任务后程序才退出,避免主程序提前退出导致未完成的goroutine产生数据竞争问题。
  2. 合理的chan使用:生产者通过select语句的default分支进行非阻塞发送,当chan满时跳过发送操作,避免了因盲目发送导致的与消费者读取操作的冲突。消费者使用for... range循环来从chan读取数据,直到chan关闭,这种方式保证了数据读取的有序性和一致性,从而避免了数据竞争。