MST

星途 面试题库

面试题:Go语言中如何通过通道机制避免常见死锁场景

在Go语言中,通道(channel)是实现并发通信的重要机制。请阐述如何合理使用通道来避免因资源竞争和同步不当导致的死锁。假设你有两个goroutine,一个负责生产数据发送到通道,另一个负责从通道接收数据,描述如何确保这个过程不会发生死锁,并给出简单示例代码。
36.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 避免死锁的方法
    • 缓冲设置:合理设置通道的缓冲区大小。如果是无缓冲通道,发送操作会阻塞直到有接收者准备好接收数据,接收操作也会阻塞直到有数据被发送。有缓冲通道则在缓冲区未满时发送操作不会阻塞,在缓冲区未空时接收操作不会阻塞。
    • 确保发送和接收的匹配:保证在所有发送操作都完成之前,有足够的接收操作;反之,在所有接收操作完成之前,有足够的发送操作。这可以通过适当的同步机制,如WaitGroup来实现。
    • 正确关闭通道:在发送端完成数据发送后,要及时关闭通道,这样接收端可以通过ok标志判断通道是否关闭,避免无限阻塞在接收操作上。
  2. 示例代码
package main

import (
    "fmt"
    "sync"
)

func producer(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < 5; i++ {
        ch <- i
    }
    close(ch)
}

func consumer(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for {
        data, ok := <-ch
        if!ok {
            break
        }
        fmt.Println("Received:", data)
    }
}

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

    wg.Add(2)
    go producer(ch, &wg)
    go consumer(ch, &wg)

    wg.Wait()
}

在上述代码中:

  • producer函数向通道ch发送数据,完成发送后关闭通道。
  • consumer函数从通道ch接收数据,当通道关闭时(okfalse)退出循环。
  • main函数使用WaitGroup等待两个goroutine完成,确保程序不会提前退出,从而避免死锁。