MST

星途 面试题库

面试题:Go中缓冲通道与非缓冲通道在数据发送接收上的区别

请详细阐述Go语言中缓冲通道与非缓冲通道在数据发送和接收操作时的行为特点及区别。
29.3万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

非缓冲通道

  1. 发送操作
    • 当向非缓冲通道发送数据时,如果没有其他 goroutine 在接收数据,发送操作会阻塞当前 goroutine,直到有其他 goroutine 准备好接收数据。例如:
package main

import (
    "fmt"
)

func main() {
    ch := make(chan int)
    go func() {
        ch <- 10 // 发送操作,如果没有接收者,这里会阻塞
    }()
    num := <-ch
    fmt.Println(num)
}
  • 在上述代码中,如果没有 num := <-ch 这一行接收操作,ch <- 10 就会一直阻塞,导致程序死锁(因为 main 函数最后也会阻塞等待所有 goroutine 结束,而这个 goroutine 又在等待接收者)。
  1. 接收操作
    • 从非缓冲通道接收数据时,如果没有其他 goroutine 在发送数据,接收操作也会阻塞当前 goroutine,直到有数据被发送进来。如上述代码中,如果没有 ch <- 10 这一行发送数据,num := <-ch 就会阻塞。
    • 非缓冲通道保证了发送和接收操作的同步性,数据从发送者直接传递到接收者,没有中间存储。

缓冲通道

  1. 发送操作
    • 向缓冲通道发送数据时,如果通道的缓冲区未满,发送操作不会阻塞,数据会被放入缓冲区。例如:
package main

import (
    "fmt"
)

func main() {
    ch := make(chan int, 2)
    ch <- 10
    ch <- 20
    fmt.Println("Data sent to buffer successfully")
}
  • 在这个例子中,通道 ch 的缓冲区大小为 2,所以可以连续发送两个数据而不阻塞。
  • 当缓冲区已满时,再进行发送操作,就会阻塞当前 goroutine,直到有其他 goroutine 从通道中接收数据,腾出空间。比如在上述代码后再添加 ch <- 30,此时就会阻塞。
  1. 接收操作
    • 从缓冲通道接收数据时,如果缓冲区中有数据,接收操作不会阻塞,会直接从缓冲区中取出数据。例如:
package main

import (
    "fmt"
)

func main() {
    ch := make(chan int, 2)
    ch <- 10
    ch <- 20
    num1 := <-ch
    fmt.Println(num1)
}
  • 这里 num1 := <-ch 会直接从缓冲区取出第一个数据 10。
  • 当缓冲区为空时,接收操作会阻塞当前 goroutine,直到有数据被发送到通道中。

两者区别总结

  1. 阻塞特性
    • 非缓冲通道在发送和接收时,如果没有对应的接收者或发送者,都会阻塞。
    • 缓冲通道在缓冲区未满时发送不阻塞,缓冲区有数据时接收不阻塞,只有在缓冲区满时发送和缓冲区空时接收才会阻塞。
  2. 数据存储
    • 非缓冲通道没有内部缓冲区,数据直接从发送者传递到接收者。
    • 缓冲通道有一个指定大小的内部缓冲区,可以临时存储数据,允许发送者在没有立即接收者的情况下发送一定数量的数据。