MST

星途 面试题库

面试题:Go通道关闭读取异常在并发场景下的处理考量

假设你正在开发一个高并发的Go程序,多个goroutine向同一个通道写入数据,然后有一个主goroutine从该通道读取数据。当所有写入goroutine完成工作并关闭通道后,主goroutine如何安全地读取完通道内剩余数据并处理可能出现的关闭读取异常?请给出代码示例并解释其原理。
48.6万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
package main

import (
    "fmt"
)

func main() {
    ch := make(chan int)

    // 模拟多个写入goroutine
    for i := 0; i < 3; i++ {
        go func(id int) {
            for j := 0; j < 3; j++ {
                ch <- id*3 + j
            }
            close(ch) // 每个写入goroutine完成工作后关闭通道
        }(i)
    }

    // 主goroutine读取通道数据
    for {
        data, ok := <-ch
        if!ok {
            // 通道关闭且数据读完
            break
        }
        fmt.Println("Received:", data)
    }
    fmt.Println("All data processed.")
}

原理解释

  1. 通道创建ch := make(chan int) 创建一个整数类型的通道 ch,用于在多个 goroutine 之间传递数据。
  2. 写入 goroutine:通过 for i := 0; i < 3; i++ 启动了3个写入 goroutine,每个 goroutine 向通道 ch 中写入3个数据,并且在完成写入后调用 close(ch) 关闭通道。注意,在实际应用中如果多个 goroutine 都尝试关闭同一个通道会导致运行时恐慌,这里由于每个 goroutine 是独立的逻辑块,在各自完成任务后关闭通道不会引发该问题。
  3. 主 goroutine 读取:主 goroutine 通过 for { data, ok := <-ch } 这种形式从通道中读取数据。ok 表示通道是否关闭且没有数据可读。当 okfalse 时,说明通道已关闭且数据已读完,此时通过 break 跳出循环,完成数据的安全读取和处理,避免了关闭读取异常。