MST

星途 面试题库

面试题:Go Channel的缓冲区与同步控制

在Go语言中,带缓冲区的channel和不带缓冲区的channel在使用上有什么区别?请编写一段代码,展示如何利用带缓冲区的channel实现多个goroutine之间的同步,要求创建5个goroutine,每个goroutine在接收到信号后执行一些简单的任务(例如打印自己的编号),最后主线程等待所有goroutine完成任务。
15.6万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

带缓冲区和不带缓冲区的channel在使用上的区别

  1. 不带缓冲区的channel
    • 发送操作(<-)和接收操作(<-)会阻塞,直到对应的接收方或发送方准备好。这意味着当一个goroutine向一个不带缓冲区的channel发送数据时,它会被阻塞,直到另一个goroutine从这个channel接收数据。同样,当一个goroutine从一个不带缓冲区的channel接收数据时,它会被阻塞,直到有另一个goroutine向这个channel发送数据。
    • 常用于实现同步通信,确保数据的发送和接收是一对一的,并且是同步进行的。
  2. 带缓冲区的channel
    • 发送操作不会立即阻塞,除非缓冲区已满。接收操作也不会立即阻塞,除非缓冲区为空。
    • 缓冲区的大小决定了可以在不阻塞的情况下发送多少个数据。例如,ch := make(chan int, 5) 创建了一个可以容纳5个 int 类型数据的带缓冲区的channel。
    • 常用于解耦发送方和接收方,允许一定程度的异步操作。

示例代码

package main

import (
    "fmt"
    "sync"
)

func worker(id int, done chan struct{}, wg *sync.WaitGroup) {
    defer wg.Done()
    <-done
    fmt.Printf("Goroutine %d received signal and is doing task\n", id)
}

func main() {
    var wg sync.WaitGroup
    done := make(chan struct{}, 5)

    for i := 1; i <= 5; i++ {
        wg.Add(1)
        go worker(i, done, &wg)
    }

    for i := 0; i < 5; i++ {
        done <- struct{}{}
    }
    close(done)
    wg.Wait()
}

在上述代码中:

  1. 我们创建了一个带缓冲区的 done channel,缓冲区大小为5。
  2. worker 函数是每个goroutine执行的函数,它等待从 done channel接收到信号,然后打印自己的编号。
  3. main 函数中,我们创建了5个goroutine,并使用 sync.WaitGroup 来等待所有goroutine完成。
  4. 通过向 done channel发送5个信号,通知所有goroutine开始执行任务,最后关闭 done channel,并等待所有goroutine完成。