MST

星途 面试题库

面试题:Go通道关闭后读取的并发场景问题

假设在一个多协程并发环境下,多个协程向同一个通道写入数据后关闭通道,另一个主协程从该通道读取数据。请描述可能出现的数据竞争问题以及如何使用同步机制来避免这些问题,并给出相应的代码示例。
41.1万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

数据竞争问题

在多协程并发环境下,多个协程向同一个通道写入数据并关闭通道时,可能出现以下数据竞争问题:

  1. 重复关闭通道:多个协程可能都尝试关闭通道,这会导致运行时恐慌(panic: close of closed channel)。
  2. 未完全写入就关闭:某个协程可能在其他协程还未完成写入数据时就关闭了通道,导致部分数据丢失。

同步机制及代码示例

为避免这些问题,可以使用sync.WaitGroup来同步协程。sync.WaitGroup用于等待一组协程完成其工作。

以下是Go语言的代码示例:

package main

import (
	"fmt"
	"sync"
)

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

	// 模拟多个协程写入数据
	for i := 0; i < 3; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			ch <- id * 10
		}(i)
	}

	// 独立的协程用于关闭通道
	go func() {
		wg.Wait()
		close(ch)
	}()

	// 主协程读取数据
	for val := range ch {
		fmt.Println("Received:", val)
	}
}

在上述代码中:

  1. sync.WaitGroup用于等待所有写入协程完成写入操作。每个写入协程开始前调用wg.Add(1),结束时调用wg.Done()
  2. 一个独立的协程等待所有写入协程完成(wg.Wait())后,关闭通道(close(ch)),这样可以避免重复关闭通道和未完全写入就关闭通道的问题。
  3. 主协程通过for... range循环从通道读取数据,直到通道关闭。