介绍

channel 在 Go 中是一种专门用来在 goroutine 之间传递数据类型安全的管道

你可以把它理解成:

  • 多个 goroutine 之间的**“传话筒”**,谁往通道里塞东西,另一个 goroutine 就能接收到。

Go 语言采用 CSP(Communicating Sequential Processes) 模型,也就是鼓励:

💡 “不要通过共享内存来通信,而要通过通信来共享内存”

也就是通过 channel 来传递数据,而不是多个 goroutine 同时操作一份共享数据,这样能减少复杂的锁。

🧬 channel 的关键特性

类型化

通道是有类型的,比如 chan int 只能传 int,chan string 只能传 string。

同步

默认情况下,不缓冲通道是同步阻塞

  • 发送方(ch <- value)如果没人接收,就等着。
  • 接收方(<- ch)如果没人发送,也等着。

缓冲区可选

你也可以给通道设置缓冲区,比如 make(chan int, 10),这样最多能存 10 个 int,不满时发送方不会阻塞。

关闭通道

当通道关闭(close(ch))后再接收,不会再阻塞,而是返回对应类型的零值和一个标志。

🎨 实际用法场景

  • 任务分发:生产者 goroutine 往通道里传任务,消费者 goroutine 从通道取任务。
  • 信号通知:用通道只传递空 struct 来通知某个 goroutine 开始或结束工作。
  • 并发控制:限制 goroutine 数量,比如用缓冲通道当作信号量。

go func()

go func() {channel <- "Hello, World!"
}()

这里启动了一个新的 goroutine 来往通道中发送数据

go func() { … }() 相当于让任务异步执行,也就是你说的 Python 里的 create_task() 或者 await 背后的任务调度

当无缓冲通道必须一手给一手拿,所以你必须用 goroutine 来让另一个任务并行接收,否则就死锁。

假设你去掉 go func(),直接写成:

channel := make(chan string)
channel <- "Hello, World!" // 直接发送
msg := <-channel
fmt.Println(msg)

那么这一行 channel <- “Hello, World!” 会一直卡住,因为:

  • 这是无缓冲通道,必须同时有接收方(也就是 <- channel)在等着。
  • 但是程序还没执行到接收方那一行,所以就死锁了。

用 go func() 把发送操作放到后台 goroutine 中,这样主 goroutine 可以继续执行接收逻辑,不再相互卡住。

换句话说:

  • goroutine A:负责发送
  • goroutine B:负责接收

如果没有 goroutine,把发送和接收写在一条顺序执行流里,就造成死锁。

❓ 所有 channel 都必须这样写吗?

不必须,取决于场景:

  • 📌 如果你用缓冲通道,也就是:
ch := make(chan string, 1)
ch <- "Hello"
msg := <-ch
  • 有缓冲,所以发送完能直接存进去,不会阻塞,这时候也可以不用 goroutine。

• 📌 如果你的接收方先执行,比如:

ch := make(chan string)
go func() {msg := <- chfmt.Println(msg)
}()
ch <- "Hello"

无缓冲通道要求

发送和接收必须成对并发执行

也可以用缓冲通道,这样中间能暂存数据,就不用 goroutine。

无缓冲通道 vs 缓冲通道

类别定义行为
无缓冲通道ch := make(chan string)必须一手交钱一手交货(也就是发送时必须有接收方正在等着),否则发送方就堵住,不往下执行
有缓冲通道ch := make(chan string, N)通道内部有个缓冲区,当缓冲区没满时可以先把数据存起来,不需要接收方马上接收,发送方能继续往下走

🔍 为什么无缓冲通道单线程会卡?

无缓冲通道相当于是零容量队列,你要往里面塞东西,但是根本没有位置存,所以必须有人正在取,这时候才成对地完成操作。

你原来的例子:

channel := make(chan string) // 无缓冲通道
channel <- "Hello" // <=== 这里堵住了
msg := <-channel

为什么堵住?

因为这一行执行时:

  • 当前 goroutine 在这里卡住,等待另一个 goroutine 来接收数据。
  • 但是你下一行还没执行,所以没有接收者!于是永远卡死。
  • 🧑‍🤝‍🧑 无缓冲通道:必须当场给对方(必须有接收者正在等)。
  • 📦 有缓冲通道:先放进快递柜(缓冲区),接收方可以迟点取。

用 Python 类比一下也许更清楚:

  • 无缓冲通道就像你用 await queue.put(),但是没有任何任务在取 → 任务永远卡在那里。
  • goroutine 就像你用 create_task() 启动另一个任务负责 queue.get(),那么 put() 就能顺利执行完。

🔥 没缓冲通道:必须有接收方同时存在,否则卡死,所以你要用 goroutine 来接收。

🔥 有缓冲通道:通道能先存东西,不必马上接收,所以可以顺利执行完发送,不用 goroutine。

普通 int 变量与 channel 的区别

对比点普通 int 变量chan int 通道
类型int 只存一个数字chan int 用来传送数字给别人
用法num := 42 然后用 numch := make(chan int) 然后用 ch <- 42 传数据
并发场景只在当前 goroutine能在多个 goroutine之间传递数据,不共享状态
行为单纯取值、赋值发送必须有接收方,不然 goroutine 会等着
目的存数据让 goroutine 之间通信

🎯 相当于什么现实场景?

💡 想象你有两个工人:

  1. 工人A(goroutine A)负责生产东西(例如生产一个数字)。
  2. 工人B(goroutine B)负责接收东西然后打印出来。

那么:

  • int num = 42 相当于是你自己手里拿着东西,没给任何人。
  • channel <- 42 相当于是你把东西放上传送带,另一个工人能从传送带拿东西,这样两个人之间就实现协作啦。

你可以用共享变量,但是:

  • 要加锁(防止读写冲突)。
  • 要自己控制什么时候生产、什么时候消费,不然很可能出错。

用 channel 你就不用自己实现这些复杂逻辑,Go 会帮你:

✅ 发送数据时自动等待接收方。

✅ 接收数据时自动等待生产方。

✅ 并发安全,不用你加锁。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/910535.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/910535.shtml
英文地址,请注明出处:http://en.pswp.cn/news/910535.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

openLayers切换基于高德、天地图切换矢量、影像、地形图层

1、需要先加载好地图&#xff0c;具体点此链接 openLayers添加天地图WMTS、XYZ瓦片服务图层、高德地图XYZ瓦片服务图层-CSDN博客文章浏览阅读31次。本文介绍了基于OpenLayers的地图交互功能实现&#xff0c;主要包括以下内容&#xff1a; 地图初始化&#xff1a;支持天地图XYZ…

springMVC-15 异常处理

异常处理-基本介绍 基本介绍 1.Spring MVC通过HandlerExceptionResolver处理程序的异常&#xff0c;包括Handler映射、数据绑定以及目标方法执行时发生的异常。 2.主要处理Handler中用ExceptionHandler注解定义的方法。 3.ExceptionHandlerMethodResolver内部若找不到Excepti…

视频汇聚EasyCVR平台v3.7.2发布:新增全局搜索、播放器默认解码方式等4大功能

EasyCVR视频汇聚平台带着全新的v3.7.2版本重磅登场&#xff01;此次升级&#xff0c;绝非简单的功能堆砌&#xff0c;而是从用户体验、操作效率以及系统性能等多维度进行的深度优化与革新&#xff0c;旨在为大家带来更加强大、稳定且高效的视频监控管理体验。 一、全局功能搜索…

三、kubectl使用详解

三、kubectl使用详解 文章目录 三、kubectl使用详解1、常用基础命令1.1 Kubectl命令格式1.2 查询一个资源1.3 创建一个资源1.4 修改一个资源1.5 删除一个资源1.6 其他 2、K8s隔离机制Namespace&#xff08;命名空间作用及使用&#xff09;2.1 什么是命名空间2.2 命名空间主要作…

JVM内存模型详解

JVM内存模型详解 Java虚拟机(JVM)内存模型是理解Java程序运行机制的核心&#xff0c;它定义了程序运行时数据的组织方式和访问规则。与Java内存模型(JMM)关注并发不同&#xff0c;JVM内存模型主要描述运行时数据区的结构和功能。 一、JVM内存模型概述 JVM内存模型将运行时数…

《对话式 AI 白皮书》共创者招募

在 AI Agent 技术不断演变的当下&#xff0c;共创一本不断演变的对话式 AI 白皮书&#xff0c;共同探索人机对话的新纪元。无论你是开发者、技术专家、生态伙伴还是创业者&#xff0c;都期待你的加入。 项目地址&#xff1a;https://github.com/RTE-Dev/book_era_convoai/ 在…

Flux功能介绍,完整使用示例,与Mono对比

以下是关于Reactor框架中Flux与Mono的功能介绍、使用示例及对比分析&#xff1a; Flux功能介绍 核心定义 Flux是Reactor库中的核心接口&#xff0c;表示一个异步的、包含零到多个元素的序列&#xff08;类似流式数据处理&#xff09;[3][4][7]。它可以处理无限长度的数据流&am…

Git使用基本指南

一、Git 基础配置 首先需要配置用户信息&#xff0c;让 Git 知道你是谁&#xff1a; git config --global user.name "你的名字" git config --global user.email "你的邮箱example.com" 如果需要查看配置信息&#xff0c;可以使用&#xff1a; git co…

【入门】【例17.3】 内功逼毒

| 时间限制&#xff1a;C/C 1000MS&#xff0c;其他语言 2000MS 内存限制&#xff1a;C/C 64MB&#xff0c;其他语言 128MB 难度&#xff1a;中等 分数&#xff1a;100 OI排行榜得分&#xff1a;12(0.1分数2难度) 出题人&#xff1a;root | 描述 黄蓉中了毒&#xff0c;在 t 时…

苹果芯片macOS安装版Homebrew(亲测)

在Linux服务器上安装一个软件常用yum&#xff0c;apt、dnf命令&#xff0c;同样macOS可以使用brew命令来安装软件。 brew会自动帮你下载、解压、安装和配置&#xff0c;更重要的是&#xff1a;它还会自动处理好软件之间的依赖关系&#xff0c;它将所有软件都安装在独立的统一目…

uniapp+vue3做小程序,获取容器高度

小程序获能用createSelectorQuery&#xff0c;如果是子组件&#xff0c;后面可以额外加一个参数in来指定获取dom的范围。小程序里面可以直接.in(this)&#xff0c;但是vue3没有this了&#xff0c;那就只能通过getCurrentInstance去获取当前实例代替this &#xff0c;注意这里需…

【网工】华为配置专题进阶篇①

目录 ■浮动路由和BFD配置 ▲浮动路由 基本配置示例 ▲BFD ▲验证命令 ▲测试连通性 ■路由综合实验RIP OSPF BGP ■浮动路由和BFD配置 ▲浮动路由 浮动路由&#xff1a;设置preference 浮动路由是一种备份路由机制&#xff0c;当主路由失效时&#xff0c;浮动路由会…

DeepLegal AI:智能法律文档审查与合规助手+MVP

1. 商业价值与市场机会 DeepLegal AI旨在革新法律行业中耗时且资源密集型的文档审查和合规流程。该应用将利用DeepSeek先进的语言模型能力&#xff0c;为律师事务所、企业法务部门和合规团队提供一个高效、准确且经济的解决方案。 市场机会&#xff1a; 法律科技市场正经历爆…

使用 Rust 编写简单计算器

在编程语言的世界中&#xff0c;Rust 以其安全性和高性能而闻名。今天&#xff0c;我们将通过一个简单的项目来探索 Rust 的魅力 —— 编写一个简单的命令行计算器。这个计算器将支持基本的算术运算&#xff08;加、减、乘、除&#xff09;&#xff0c;并且可以通过用户输入进行…

清华大学:《AI赋能教育 :高考志愿填报工具使用指南》下载

志愿填报的认知革命已经到来 “分数出来了&#xff0c;但不知道能上什么学校……” “喜欢这个专业&#xff0c;但不知道就业前景怎么样&#xff1f;” “到底是选热门专业还是选兴趣爱好&#xff1f;” 这些让百万家庭彻夜难眠的问题&#xff0c;你是否正在经历&#xff1f; …

【科技公司的管理】

如何打造高效、人性化的目标驱动型公司&#xff1f;——OKR管理法绩效薪酬体系全指南 你希望公司目标清晰、员工高效、多劳多得&#xff0c;同时避免马斯克式的“冷血管理”&#xff0c;兼顾员工生活需求。以下是系统性解决方案&#xff0c;涵盖目标设定&#xff08;OKR&#x…

小白成长之路--nginx基础配置(一)

文章目录 一、概述1.1 Nginx 特点1.2 Nginx 作用1.3Nginx工作原理 二、Nginx服务搭建2.1安装2.2 目录结构2.3 配置文件作用2.4 nginx,conf配置文件详解2.5 核心命令2.6 Nginx信号三.Nginx3.1启动 总结 一、概述 Nginx 是开源、高性能、高可靠的 Web服务器 和反向代理服务器&am…

从最基础的float布局开始学前端

前端学习其实不难&#xff0c;我们先从float布局讲起&#xff0c;写一个最简单的导航栏&#xff1a;Logo在左&#xff0c;导航链接在右。下面是示例代码&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"…

12. TypeScript 高级类型

TypeScript 中的高级类型包括映射类型、条件类型、字面量类型和递归类型等强大结构。这些特性使开发者能够表达类型之间更复杂的关系&#xff0c;从而处理边缘情况&#xff0c;并定义更动态、更灵活的类型系统。 一、映射类型 TypeScript 映射类型&#xff08;Mapped Types&a…

韩国证券交易所(KRX)全生态接入系统技术白皮书

核心价值&#xff1a;为全球最活跃的衍生品市场&#xff08;日均交易量480亿美元&#xff09;提供 5μs延迟引擎全合规认证&#xff0c;助力中资机构抢占韩国78%衍生品交易份额 一、KRX市场机遇与准入壁垒 1.1 核心数据锚定&#xff08;2025Q2&#xff09; 指标数值全球竞争力…