MST

星途 面试题库

面试题:Go语言中通道死锁的常见场景及避免方法

请描述在Go语言中,哪些常见场景可能会导致通道死锁?并举例说明如何通过合理的代码设计来避免这些死锁场景。
47.7万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

常见导致通道死锁的场景:

  1. 发送端无接收方:当一个协程向通道发送数据,但没有其他协程从该通道接收数据时,会发生死锁。例如:
package main

func main() {
    ch := make(chan int)
    ch <- 1 // 这里发送数据,但没有接收方,会导致死锁
}
  1. 接收端无发送方:当一个协程尝试从通道接收数据,但没有其他协程向该通道发送数据时,会发生死锁。例如:
package main

func main() {
    ch := make(chan int)
    <-ch // 这里接收数据,但没有发送方,会导致死锁
}
  1. 双向阻塞:在两个协程之间通过通道进行通信时,如果双方都在等待对方先操作,会导致死锁。例如:
package main

import (
    "fmt"
)

func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)

    go func() {
        ch1 <- 1
        <-ch2
    }()

    go func() {
        ch2 <- 2
        <-ch1
    }()
}

避免死锁的代码设计方法:

  1. 确保有接收方:在发送数据之前,确保有协程准备好从通道接收数据。例如:
package main

import (
    "fmt"
)

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

    go func() {
        data := <-ch
        fmt.Println("Received:", data)
    }()

    ch <- 1
}
  1. 确保有发送方:在接收数据之前,确保有协程准备好向通道发送数据。例如:
package main

import (
    "fmt"
)

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

    go func() {
        ch <- 1
    }()

    data := <-ch
    fmt.Println("Received:", data)
}
  1. 避免双向阻塞:合理设计协程间的通信逻辑,避免双方互相等待。例如,通过引入一个额外的信号通道来打破死锁:
package main

import (
    "fmt"
)

func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)
    signal := make(chan struct{})

    go func() {
        <-signal
        ch1 <- 1
        <-ch2
    }()

    go func() {
        ch2 <- 2
        <-ch1
        close(signal)
    }()

    close(signal)
}