MST
星途 面试题库

面试题:Go中channel关闭与select语句的协同应用

假设有多个goroutine向一个channel发送数据,有一个主goroutine从该channel接收数据。请描述如何优雅地关闭这个channel,使得主goroutine能正确接收到所有数据,并且不发生数据丢失或死锁。同时,在代码中展示如何通过`select`语句配合`close`操作实现这个功能。
31.2万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 关闭channel的策略
    • 当所有发送数据的goroutine都完成数据发送后,关闭channel。为了确保所有发送goroutine都完成,可以使用sync.WaitGroup来等待所有发送goroutine结束。
    • 主goroutine通过select语句的case来接收数据,并通过ok值判断channel是否关闭。当okfalse时,说明channel已关闭,此时主goroutine可以安全退出接收循环。
  2. 代码示例
package main

import (
    "fmt"
    "sync"
)

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

    // 模拟多个发送数据的goroutine
    numSenders := 3
    for i := 0; i < numSenders; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            for j := id * 10; j < (id+1)*10; j++ {
                ch <- j
            }
        }(i)
    }

    go func() {
        wg.Wait()
        close(ch)
    }()

    // 主goroutine接收数据
    for {
        select {
        case val, ok := <-ch:
            if!ok {
                fmt.Println("Channel is closed, exiting receive loop")
                return
            }
            fmt.Println("Received:", val)
        }
    }
}

在上述代码中:

  • 首先创建了一个WaitGroup和一个channel。
  • 启动多个goroutine向channel发送数据,每个goroutine使用wg.Add(1)wg.Done()来标记开始和结束。
  • 一个匿名goroutine使用wg.Wait()等待所有发送goroutine完成,然后关闭channel。
  • 主goroutine通过select语句接收数据,当okfalse时退出接收循环,确保不会丢失数据或发生死锁。