有缓存的channel与无缓存的channel

在 Go 中,有缓存的 channel(也称为带缓冲的 channel)和普通的 channel无缓冲 channel)在行为上有显著的区别:

无缓冲 Channel

  • 定义:无缓冲 channel 是一种在发送和接收操作时必须匹配的 channel。即,发送操作会被阻塞,直到有接收方准备好接收数据,反之亦然。
  • 创建make(chan Type),例如:make(chan int)
  • 特性
    • 发送操作在接收操作之前必须等待。
    • 接收操作在发送操作之前必须等待。
    • 适用于需要确保同步的场景,比如确保发送者和接收者严格对齐数据流。

 

有缓存的 Channel

  • 定义:有缓存的 channel 具有指定的缓冲区大小,这允许发送操作在没有接收方时继续执行,直到缓冲区满。
  • 创建make(chan Type, capacity),例如:make(chan int, 10) 表示创建一个容量为 10 的缓存 channel。
  • 特性
    • 发送操作在缓冲区未满时可以立即完成,而不需要等待接收操作。
    • 接收操作在缓冲区不空时可以立即完成,而不需要等待发送操作。
    • 可以处理多生产者、多消费者模式,缓冲可以提高性能,减少阻塞。

主要区别

  1. 阻塞行为

    • 无缓冲 channel:发送和接收操作都必须匹配,发送会阻塞直到有接收方,接收会阻塞直到有发送方。
    • 有缓存的 channel:发送操作在缓冲区未满时不会阻塞,接收操作在缓冲区不空时不会阻塞。
  2. 容量

    • 无缓冲 channel:容量为 0。
    • 有缓存的 channel:具有指定的缓冲区大小。
  3. 用途

    • 无缓冲 channel:适用于需要严格同步的场景。
    • 有缓存的 channel:适用于需要处理大量数据的场景,或者需要减少阻塞和等待的场景。
      复制代码
      // 无缓冲 channel 示例
      ch := make(chan int)
      go func() {
          ch <- 1 // 发送会阻塞,直到有接收方
      }()
      fmt.Println(<-ch) // 接收会阻塞,直到有发送方
      
      // 有缓存的 channel 示例
      ch := make(chan int, 2) // 缓冲区容量为 2
      ch <- 1  // 发送不会阻塞,直到缓冲区满
      ch <- 2  // 继续发送不会阻塞
      // ch <- 3  // 会阻塞,直到有接收方
      fmt.Println(<-ch) // 接收不会阻塞,直到缓冲区有数据
      fmt.Println(<-ch) // 接收继续,不会阻塞
      复制代码



question: 无缓冲通道必须在单独goroutine工作,在main中会死锁,这个观点是对是错?

复制代码
package main

import (
    "fmt"
)

func main() {
    ch := make(chan int) // 无缓冲 channel

    // 在 main goroutine 中执行发送和接收操作
    ch <- 1 // 这里会阻塞,因为没有接收方
    fmt.Println(<-ch) // 这个接收操作也会阻塞,因为发送方没有准备好

    // 程序将会在发送操作处死锁
}
复制代码

answer:

这个观点是对的。无缓冲 channel 的发送和接收操作必须在不同的 goroutine 中进行,否则会导致死锁。原因如下:

无缓冲 Channel 死锁情况

无缓冲 channel 需要发送和接收操作同时进行,否则会出现死锁。具体来说:

  1. 发送操作:发送方会阻塞,直到接收方准备好接收数据。
  2. 接收操作:接收方会阻塞,直到发送方发送数据。

如果在同一个 goroutine 中执行发送和接收操作,发送操作会因为没有接收方而阻塞,而接收操作也会因为没有发送方而阻塞。这会导致程序无法继续执行,出现死锁。

解决:

复制代码
package main

import (
    "fmt"
)

func main() {
    ch := make(chan int) // 无缓冲 channel

    go func() {
        ch <- 1 // 发送数据到 channel
    }()

    fmt.Println(<-ch) // 从 channel 中接收数据
}
复制代码

 




posted @   你脑子有bug  阅读(247)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示