如果是无缓冲类型管道? 读取和有缓冲的区别?

无缓冲管道(Unbuffered Channel)与有缓冲管道(Buffered Channel)在Go语言中的主要区别在于它们对数据传输的同步性和容量:

  1. 无缓冲管道

    • 数据传输是同步的,即在无缓冲管道中,发送和接收操作是严格配对的,发送操作会一直阻塞,直到接收方准备好并从管道中接收了数据。
    • 当向无缓冲管道中发送数据时,如果没有接收方正在等待接收数据,发送操作会立即阻塞,直到有接收者准备接收为止。
    • 类似地,接收操作也会阻塞,直到有发送者发送数据到管道中。
  2. 有缓冲管道

    • 数据传输可以是异步的,管道内部有一定的存储空间(缓冲区),允许暂时存储一些数据。
    • 当向有缓冲管道发送数据时,只要缓冲区未满,数据就能立即存入管道,不会阻塞发送者,只有当缓冲区满时,后续的发送操作才会阻塞。
    • 接收数据时,如果缓冲区中有数据,接收操作可以立即获取并移除数据,如果缓冲区为空,接收操作才会阻塞,等待数据到来。

简单来说,无缓冲管道强制实现了严格的同步行为,适合需要严格保证顺序执行的场景,而有缓冲管道允许一定程度的异步执行,提高了并发性能和灵活性,适合处理突发流量或者多个生产者和消费者之间有短暂时间差的情况。

select监听多个管道

在Go语言中,select语句用于监听多个通道(channel)的操作。它的工作方式类似于switch语句,但它不是根据表达式的值进行判断,而是根据所监听的通道是否准备好进行通信(发送或接收)。

select语句的基本语法如下:

select {
case communicationClause1:
    statement1
case communicationClause2:
    statement2
...
default:
    defaultStatement // 可选,如果没有通道准备好,则执行此分支
}

每个communicationClause通常由一个channel的发送或接收操作组成,例如:

ch1 := make(chan int)
ch2 := make(chan string)

select {
case i := <-ch1: // 从ch1接收数据
    fmt.Println("Received", i, "from ch1")
case ch2 <- "Hello": // 向ch2发送数据
    fmt.Println("Sent 'Hello' to ch2")
default:
    fmt.Println("No channel is ready")
}

select被执行时,它会等待所有的case中至少有一个通道准备好执行其操作。如果有多个通道同时准备好,Go runtime会选择一个非随机的(但从实现角度看可能是伪随机的)通道执行。如果没有通道准备好,而default分支存在的话,就会执行default分支的语句。如果没有default分支且所有通道均未准备好,则select会阻塞,直到至少有一个通道变为可读或可写状态。

注意,select语句在多路复用场景中特别有用,尤其在并发编程中处理多个并发通道间的通信同步时。

最后编辑: kuteng  文档更新时间: 2024-04-02 09:53   作者:kuteng