go channel 的用法和核心原理、使用场景
一、Channel 的核心用法
1. 基本操作
// 创建无缓冲 Channel(同步通信)
ch := make(chan int)
// 创建有缓冲 Channel(容量为5,异步通信)
bufferedCh := make(chan int, 5)
// 发送数据到 Channel
ch <- 42
// 从 Channel 接收数据
value := <-ch
// 关闭 Channel(只能由发送方关闭)
close(ch)
2. 单向 Channel(类型安全)
// 只写 Channel
func producer(ch chan<- int) {
ch <- 1
}
// 只读 Channel
func consumer(ch <-chan int) {
fmt.Println(<-ch)
}
3. 多路复用(select)
select {
case v := <-ch1:
fmt.Println(v)
case ch2 <- 42:
fmt.Println(“sent”)
case <-time.After(time.Second):
fmt.Println(“timeout”)
default:
fmt.Println(“no activity”)
}
4. 遍历 Channel
// 自动检测 Channel 关闭
for v := range ch {
fmt.Println(v)
}
二、Channel 的核心原理
1. 底层数据结构
Channel 在运行时由 hchan 结构体表示(简化版):
type hchan struct {
qcount uint // 当前元素数量
dataqsiz uint // 缓冲区大小(容量)
buf unsafe.Pointer // 环形缓冲区指针
elemsize uint16 // 元素类型大小
closed uint32 // 关闭标志
sendx uint // 发送索引
recvx uint // 接收索引
recvq waitq // 接收等待队列(sudog链表)
sendq waitq // 发送等待队列(sudog链表)
lock mutex // 互斥锁
}
2. 操作流程
- 发送数据:
- 缓冲区有空位:直接写入缓冲区。
- 缓冲区已满:当前 Goroutine 被加入
sendq队列并阻塞(gopark)。 - 有等待的接收者:直接将数据拷贝到接收方,唤醒接收者(
goready)。
- 接收数据:
- 缓冲区有数据:直接读取。
- 缓冲区为空:当前 Goroutine 被加入
recvq队列并阻塞。 - 有等待的发送者:直接从发送者拷贝数据,唤醒发送者。
3. 关键机制
- 同步(无缓冲):发送和接收必须同时就绪,否则阻塞。
- 异步(有缓冲):缓冲区未满/非空时操作立即完成。
- 关闭 Channel:
- 关闭后发送操作会触发
panic。 - 接收操作会立即返回剩余数据,之后返回零值。
- 关闭后发送操作会触发
- Goroutine 调度:通过
gopark和goready实现阻塞和唤醒。
三、Channel 的使用场景
1. 任务分发与结果收集
// Worker Pool 模式
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
results <- j * 2
}
}
func main() {
jobs := make(chan int, 10)
results := make(chan int, 10)
// 启动3个 Worker
for w := 1; w <= 3; w++ {go worker(w, jobs, results)
}// 分发任务
for j := 1; j <= 5; j++ {jobs <- j
}
close(jobs)// 收集结果
for i := 1; i <= 5; i++ {fmt.Println(<-results)
}
}
2. 事件通知
// 使用关闭 Channel 广播事件
var done = make(chan struct{})
func worker() {
for {
select {
case <-done:
fmt.Println(“exit”)
return
default:
// 正常工作
}
}
}
// 关闭 Channel 通知所有 Worker 退出
close(done)
3. 并发控制(信号量)
// 限制并发数为3
var sem = make(chan struct{}, 3)
func task() {
sem <- struct{}{} // 获取信号量
defer func() { <-sem }() // 释放信号量
// 执行任务
}
4. 数据流水线
// 流水线处理:生成 → 平方 → 输出
func gen(nums …int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func sq(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n
}
close(out)
}()
return out
}
func main() {
// 流水线连接
c := gen(2, 3)
out := sq©
for n := range out {
fmt.Println(n) // 4, 9
}
}
四、注意事项
- 关闭 Channel:
- 只有发送方可以关闭 Channel。
- 重复关闭会触发
panic。
- 阻塞与死锁:
- 确保有 Goroutine 接收发送的数据。
- 零值 Channel:
- 从
nilChannel 接收或发送会永久阻塞。
- 从
- 性能优化:
- 小对象直接传递,大对象传递指针。
- 避免频繁创建和销毁 Channel。
相关文章:
go channel 的用法和核心原理、使用场景
一、Channel 的核心用法 1. 基本操作 // 创建无缓冲 Channel(同步通信) ch : make(chan int) // 创建有缓冲 Channel(容量为5,异步通信) bufferedCh : make(chan int, 5) // 发送数据到 Channel ch <- 42 // 从…...
pyside6学习专栏(七):自定义QTableWidget的扩展子类QTableWidgetEx
PySide6界面编程中较常用的控件还有QTableWidget表格控件,用来将加载的数据在表格中显示出来,下面继承QTableWidget编写其扩展子类QTableWidgetEx,来实现用单元格来显示除数据文字外,还可以对表格的单元格的文字颜色、背景底色进行设置&#…...
Mybatis常用动态 SQL 相关标签
1. <if> 用于条件判断,当满足条件时执行对应的 SQL 片段。 示例: <select id"findUser" resultType"User">SELECT * FROM usersWHERE 11<if test"name ! null and name ! ">AND name #{name}</if><if…...
AWQ和GPTQ量化的区别
一、前言 本地化部署deepseek时发现,如果是量化版的deepseek,会节约很多的内容,然后一般有两种量化技术,那么这两种量化技术有什么区别呢? 二、量化技术对比 在模型量化领域,AWQ 和 GPTQ 是两种不同的量…...
ESP32S3:解决RWDT无法触发中断问题,二次开发者怎么才能使用内部RTC看门狗中断RWDT呢?
目录 基于ESP32S3:解决RWDT无法触发中断问题引言解决方案1. 查看报错日志2. 分析报错及一步一步找到解决方法3.小结我的源码基于ESP32S3:解决RWDT无法触发中断问题 引言 在嵌入式系统中,RWDT(看门狗定时器)是确保系统稳定性的重要组件。然而,在某些情况下,RWDT可能无法…...
基于SpringBoot的民宿管理系统的设计与实现(源码+SQL脚本+LW+部署讲解等)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...
go 日志框架
内置log import ("log""os" )func main() {// 设置loglog.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate)// 自定义日志前缀log.SetPrefix("[pprof]")log.Println("main ..")// 如果用format就用PrintF,而不是…...
如何在 PDF 文件中嵌入自定义数据
由于 PDF 文件格式功能强大且灵活,它经常被用于内部工作流程。有时候,将自定义数据嵌入 PDF 文件本身会非常有用。通常,这些信息会被大多数工具忽略,因此 PDF 仍然可以作为普通 PDF 文件正常使用。 以下是一些实现方法࿱…...
计算机毕业设计SpringBoot+Vue.js服装商城 服装购物系统(源码+LW文档+PPT+讲解+开题报告)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
22.回溯算法4
递增子序列 这里不能排序,因为数组的顺序是对结果有影响的,所以只能通过used数组来去重 class Solution { public:vector<int> path;vector<vector<int>> res;void backtracking(vector<int>& nums,int start){if(path.si…...
linux -对文件描述符的操作dup、fcntl有五种
dup #include<unistd.h> int dup(int oldfd);作用:复制一个新的文件描述符fd 3, int fd1 dup(fd);f指向的是a.txt,fd1指向的也是a.txt从空闲的文件描述符表中找一个最小的作为新的拷贝的文件描述符返回:成功返回新的文件描述符,失败…...
技术解析 | 适用于TeamCity的Unreal Engine支持插件,提升游戏构建效率
龙智是JetBrains授权合作伙伴、Perforce授权合作伙伴,为您提供TeamCity、Perforce Helix Core等热门的游戏开发工具及一站式服务 TeamCity 是游戏开发的热门选择,大家选择它的原因包括支持 Perforce、可以进行本地安装,并提供了多种配置选项。…...
Ubuntu22.04 - brpc的安装和使用
目录 介绍安装使用 介绍 brpc 是用 c语言编写的工业级 RPC 框架,常用于搜索、存储、机器学习、广告、推荐等高性能系统 安装 先安装依赖 apt-get install -y git g make libssl-dev libprotobuf-dev libprotoc-dev protobuf-compiler libleveldb-dev libgflags-d…...
网络运维学习笔记 018 HCIA-Datacom综合实验02
文章目录 综合实验2sw3:sw4:gw:core1(sw1):core2(sw2):ISP 综合实验2 sw3: vlan 2 stp mode stp int e0/0/1 port link-type trunk port trunk allow-pass v…...
Vulhub靶机 Apache Druid(CVE-2021-25646)(渗透测试详解)
一、开启vulhub环境 docker-compose up -d 启动 docker ps 查看开放的端口 1、漏洞范围 在Druid0.20.0及更低版本中 二、访问靶机IP 8888端口 1、点击Load data进入新界面后,再点击local disk按钮。 2、进入新界面后,在标红框的Base directory栏写上…...
VSCode配置自动生成头文件
一、配置步骤: 1.打开命令面板(CtrlShiftp): 2.输入snippets 选择配置代码片段 3. 选择新建全局代码片段 输入文件名,比如header_cpp(随便定义),然后点击键盘回车按钮,得到下面这个文件。 增加配置文…...
Xcode如何高效的一键重命名某个关键字
1.选中某个需要修改的关键字; 2.右击,选择Refactor->Rename… 然后就会出现如下界面: 此时就可以一键重命名了。 还可以设置快捷键。 1.打开Settings 2.找到Key Bindings 3.搜索rename 4.出现三个,点击一个地方设置后其…...
React 高阶组件的优缺点
React 高阶组件的优缺点 优点 1. 代码复用性高 公共逻辑封装:当多个组件需要实现相同的功能或逻辑时,高阶组件可以将这些逻辑封装起来,避免代码重复。例如,多个组件都需要在挂载时进行数据获取操作,就可以创建一个数…...
(五)趣学设计模式 之 建造者模式!
目录 一、 啥是建造者模式?二、 为什么要用建造者模式?三、 建造者模式怎么实现?四、 建造者模式的应用场景五、 建造者模式的优点和缺点六、 总结 🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方…...
香橙派/树莓派 利用Wiring库 使用GPIO模拟PWM
香橙派或者树莓派 等开发板,本身带有硬件PWM,比如香橙派3 lts版,但是这个引脚不符合我的项目需求,我需要外接一个电机,在检测到人脸的时候 转动,但是这个硬件引脚,只要上电就开始输出pwm 信号,导…...
Claude Code 启动失败修复指南
Claude Code 启动失败修复指南 问题现象 在 Windows 系统上运行 claude 命令时出现以下错误: 程序"claude.exe"无法运行: 指定的可执行文件不是此操作系统平台的有效应用程序。 所在位置 C:\Users\XX\AppData\Roaming\npm\claude.ps1:14 字符: 3& &qu…...
如何修复 Flexbox 布局在移动端失效的问题:关键在于容器宽度与响应式约束
本文详解为何基于 Flexbox 构建的输入框组件在桌面端正常、却在移动端布局错乱,并给出精准修复方案——核心是为 .inputs 容器显式声明 width: 100%,同时补充 viewport 设置、弹性子项行为修正及移动端交互优化建议。 本文详解为何基于 flexbox 构建…...
飞秋Mac版:终极开源局域网通信工具完全指南
飞秋Mac版:终极开源局域网通信工具完全指南 【免费下载链接】feiq 基于qt实现的mac版飞秋,遵循飞秋协议(飞鸽扩展协议),支持多项飞秋特有功能 项目地址: https://gitcode.com/gh_mirrors/fe/feiq 飞秋Mac版是基于Qt框架开发的跨平台局…...
ViGEmBus虚拟游戏控制器驱动:终极安装与完整使用指南
ViGEmBus虚拟游戏控制器驱动:终极安装与完整使用指南 【免费下载链接】ViGEmBus Windows kernel-mode driver emulating well-known USB game controllers. 项目地址: https://gitcode.com/gh_mirrors/vi/ViGEmBus 你是否曾经遇到过这样的烦恼?想…...
别再只用ECharts画平面地图了!Vue3项目里给中国地图加上3D流线动画(附完整源码)
Vue3与ECharts 5打造3D流线地图:从平面到立体的视觉革命 在数据可视化领域,地图展示早已超越了简单的区域划分功能。当大多数开发者还在使用ECharts绘制基础平面地图时,前沿项目已经开始追求更具沉浸感的3D视觉体验。想象一下:在智…...
2025最权威的六大AI辅助写作神器解析与推荐
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 人工智能技术飞速发展的当下,AI辅助学术写作成了研究热点,借助AI撰写…...
南宁宠物医院哪家好
在南宁这座充满活力的城市里,宠物已经成为许多家庭不可或缺的一员。当毛孩子出现健康问题时,选择一家值得信赖的宠物医院成为宠物主人的首要任务。今天,让我们一同走进广西阿荣宠物医院,了解这家陪伴宠物和主人走过13年时光的医疗…...
保姆级教程:在Ubuntu 20.04上搞定GAMIT/GLOBK 10.7安装(含gfortran版本避坑指南)
保姆级教程:在Ubuntu 20.04上搞定GAMIT/GLOBK 10.7安装(含gfortran版本避坑指南) 如果你正在Ubuntu 20.04上尝试安装GAMIT/GLOBK 10.7,却因为各种依赖问题和版本冲突而头疼不已,那么这篇教程就是为你准备的。作为一款强…...
SiameseUIE模型在网络安全领域的应用:威胁情报抽取
SiameseUIE模型在网络安全领域的应用:威胁情报抽取 网络安全分析师每天都要面对海量的威胁情报报告、安全日志和漏洞公告。这些文本数据里藏着攻击者的IP地址、恶意域名、攻击手法、漏洞编号等关键信息。传统做法是人工逐篇阅读、标记、整理,不仅效率低…...
GD32F407 USB CDC虚拟串口调试实战:从枚举失败到稳定收发数据的避坑指南
GD32F407 USB CDC开发实战:从设备枚举到数据收发的深度排错手册 当你的GD32F407开发板通过USB线连接到电脑,却始终无法在设备管理器中出现那个期待的"USB串行设备"图标时,这种挫败感每个嵌入式开发者都深有体会。本文将以一个真实的…...
