MST
星途 面试题库

面试题:Go中生产者消费者模式下,如何使用Buffered Channel优化性能

在一个高并发场景下的Go生产者消费者模式程序中,现有的无缓冲Channel在数据传输时出现了性能瓶颈。请分析使用Buffered Channel进行优化的原理,并修改原代码以展示如何通过设置合适的缓冲区大小来提升整体性能。假设生产者每秒产生1000个数据,消费者处理每个数据平均需要10毫秒。
32.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

原理分析

  1. 无缓冲Channel的问题:无缓冲Channel在发送数据时,必须要有对应的接收方准备好接收,否则发送操作会阻塞。在高并发场景下,若生产者生产数据速度快于消费者消费速度,生产者会频繁阻塞等待消费者接收数据,导致整体性能瓶颈。
  2. Buffered Channel的优势:Buffered Channel有一定大小的缓冲区,生产者可以先将数据发送到缓冲区,而无需等待消费者立即接收。只有当缓冲区满时,生产者才会阻塞。这允许生产者和消费者在一定程度上异步工作,减少生产者的阻塞时间,提升整体性能。

代码修改

package main

import (
    "fmt"
    "sync"
    "time"
)

func producer(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; ; i++ {
        ch <- i
        time.Sleep(time.Millisecond * 1) // 模拟每秒产生1000个数据
    }
}

func consumer(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for data := range ch {
        fmt.Printf("Consumed: %d\n", data)
        time.Sleep(time.Millisecond * 10) // 模拟处理每个数据平均需要10毫秒
    }
}

func main() {
    var wg sync.WaitGroup
    // 计算缓冲区大小:消费者每秒能处理100个数据(1000ms / 10ms),生产者每秒产生1000个数据,所以至少需要900大小的缓冲区来避免生产者频繁阻塞
    ch := make(chan int, 900) 

    wg.Add(1)
    go producer(ch, &wg)

    wg.Add(1)
    go consumer(ch, &wg)

    time.Sleep(time.Second * 10) // 运行10秒
    close(ch)
    wg.Wait()
}

在上述代码中,make(chan int, 900) 创建了一个缓冲区大小为900的Buffered Channel。这个大小是基于生产者每秒产生1000个数据,消费者每秒能处理100个数据(1000ms / 10ms)计算得出的,以尽量避免生产者频繁阻塞,提升整体性能。