Go channel发送和接收什么情况下会死锁?

参考解析

死锁:

  • 单个协程永久阻塞
  • 两个或两个以上的协程的执行过程中,由于竞争资源或由于彼此通信而造成的一种阻塞的现象。

channel死锁场景:

  • 非缓存channel只写不读
  • 非缓存channel读在写后面
  • 缓存channel写入超过缓冲区数量
  • 空读
  • 多个协程互相等待
  1. 非缓存channel只写不读
  1. func deadlock1() {
  2. ch := make(chan int)
  3. ch <- 3 // 这里会发生一直阻塞的情况,执行不到下面一句
  4. }
  1. 非缓存channel读在写后面

    1. func deadlock2() {
    2. ch := make(chan int)
    3. ch <- 3 // 这里会发生一直阻塞的情况,执行不到下面一句
    4. num := <-ch
    5. fmt.Println("num=", num)
    6. }
    7. func deadlock2() {
    8. ch := make(chan int)
    9. ch <- 100 // 这里会发生一直阻塞的情况,执行不到下面一句
    10. go func() {
    11. num := <-ch
    12. fmt.Println("num=", num)
    13. }()
    14. time.Sleep(time.Second)
    15. }
  2. 缓存channel写入超过缓冲区数量

    1. func deadlock3() {
    2. ch := make(chan int, 3)
    3. ch <- 3
    4. ch <- 4
    5. ch <- 5
    6. ch <- 6 // 这里会发生一直阻塞的情况
    7. }
  3. 空读

    1. func deadlock4() {
    2. ch := make(chan int)
    3. // ch := make(chan int, 1)
    4. fmt.Println(<-ch) // 这里会发生一直阻塞的情况
    5. }
  4. 多个协程互相等待

    1. func deadlock5() {
    2. ch1 := make(chan int)
    3. ch2 := make(chan int)
    4. // 互相等对方造成死锁
    5. go func() {
    6. for {
    7. select {
    8. case num := <-ch1:
    9. fmt.Println("num=", num)
    10. ch2 <- 100
    11. }
    12. }
    13. }()
    14. for {
    15. select {
    16. case num := <-ch2:
    17. fmt.Println("num=", num)
    18. ch1 <- 300
    19. }
    20. }
    21. }