当前位置: 首页 > news >正文

回顾Golang的Channel与Select第二篇

深入掌握Go Channel与Select:从原理到生产级实践

一、Channel基础:不只是数据管道

1.1 通道的完整生命周期(可运行示例)

package mainimport ("fmt""time"
)func main() {// 创建缓冲通道ch := make(chan int, 3)// 生产者go func() {for i := 1; i <= 5; i++ {ch <- ifmt.Printf("Sent: %d\n", i)}close(ch) // 正确关闭姿势}()// 消费者go func() {for {val, ok := <-chif !ok {fmt.Println("Channel closed!")return}fmt.Printf("Received: %d\n", val)time.Sleep(500 * time.Millisecond) // 模拟处理耗时}}()time.Sleep(3 * time.Second) // 保证演示完整
}

运行结果:

Sent: 1
Sent: 2
Sent: 3
Received: 1
Sent: 4
Received: 2
Sent: 5
Received: 3
Received: 4
Received: 5
Channel closed!

1.2 通道的四种致命操作(包含错误示例)

package mainfunc main() {// 示例1:关闭已关闭的通道ch1 := make(chan int)close(ch1)// close(ch1) // 运行时panic// 示例2:向已关闭通道发送数据ch2 := make(chan int)go func() { ch2 <- 1 }()close(ch2)// ch2 <- 2 // 运行时panic// 示例3:未初始化的通道var ch3 chan int// ch3 <- 1 // 永久阻塞// <-ch3    // 永久阻塞// 示例4:未关闭导致的内存泄漏ch4 := make(chan int)go func() {<-ch4 // 永远阻塞}()// 忘记关闭导致goroutine泄漏
}

二、Select高级模式:并发控制的艺术

2.1 超时控制完整实现

package mainimport ("fmt""math/rand""time"
)func main() {rand.Seed(time.Now().UnixNano())operation := func() chan string {ch := make(chan string)go func() {delay := time.Duration(rand.Intn(1500)) * time.Millisecondtime.Sleep(delay)ch <- "operation completed"}()return ch}select {case res := <-operation():fmt.Println(res)case <-time.After(1 * time.Second):fmt.Println("Timeout!")}
}

2.2 多通道联合模式(可运行工作池)

package mainimport ("fmt""sync""time"
)func WorkerPool() {const workerCount = 3const taskCount = 10taskCh := make(chan int, 5)doneCh := make(chan struct{}, workerCount)var wg sync.WaitGroup// 启动工作池for i := 0; i < workerCount; i++ {wg.Add(1)go func(id int) {defer wg.Done()for task := range taskCh {fmt.Printf("Worker %d processing task %d\n", id, task)time.Sleep(time.Duration(task%3+1) * time.Second)doneCh <- struct{}{}}}(i)}// 分发任务go func() {for i := 1; i <= taskCount; i++ {taskCh <- i}close(taskCh)}()// 进度监控go func() {count := 0for range doneCh {count++fmt.Printf("Completed %d/%d tasks\n", count, taskCount)if count == taskCount {close(doneCh)}}}()wg.Wait()fmt.Println("All tasks completed!")
}func main() {WorkerPool()
}

三、通道性能优化实战

3.1 批处理模式对比测试

package mainimport ("fmt""testing""time"
)func BenchmarkSingleProcess(b *testing.B) {ch := make(chan int)go func() {for i := 0; i < b.N; i++ {ch <- i}close(ch)}()for range ch {// 模拟处理单个元素time.Sleep(1 * time.Nanosecond)}
}func BenchmarkBatchProcess(b *testing.B) {ch := make(chan []int, 100)go func() {batch := make([]int, 0, 1000)for i := 0; i < b.N; i++ {batch = append(batch, i)if len(batch) == 1000 {ch <- batchbatch = make([]int, 0, 1000)}}if len(batch) > 0 {ch <- batch}close(ch)}()for batch := range ch {// 模拟批量处理time.Sleep(time.Duration(len(batch)) * time.Nanosecond)}
}func main() {fmt.Println("Single Process:")fmt.Println(testing.Benchmark(BenchmarkSingleProcess))fmt.Println("\nBatch Process:")fmt.Println(testing.Benchmark(BenchmarkBatchProcess))
}

典型测试结果:

Single Process:
BenchmarkSingleProcess-8         1000000              1045 ns/op
Batch Process:
BenchmarkBatchProcess-8           100000             10312 ns/op (等效103 ns/op)

四、通道与内存模型:Happens-Before保证

4.1 内存可见性保证示例

package mainimport ("fmt""time"
)var data int
var ready = make(chan struct{})func writer() {data = 42close(ready) // 关闭操作作为同步点
}func reader() {<-readyfmt.Println("Data:", data) // 保证输出42
}func main() {go writer()go reader()time.Sleep(1 * time.Second)
}

4.2 双重检查锁模式(通道实现版)

package mainimport ("fmt""sync"
)type Singleton struct {value int
}var instance *Singleton
var once sync.Once
var instanceCh = make(chan *Singleton)func GetInstance() *Singleton {once.Do(func() {go func() {instance = &Singleton{value: 42}instanceCh <- instance}()})return <-instanceCh
}func main() {var wg sync.WaitGroupfor i := 0; i < 5; i++ {wg.Add(1)go func() {defer wg.Done()inst := GetInstance()fmt.Printf("Instance address: %p\n", inst)}()}wg.Wait()
}

五、错误处理模式

5.1 错误聚合通道

package mainimport ("errors""fmt""sync"
)func parallelTasks() ([]int, error) {const workers = 5results := make(chan int, workers)errCh := make(chan error, 1)var wg sync.WaitGroupfor i := 0; i < workers; i++ {wg.Add(1)go func(id int) {defer wg.Done()if id == 2 { // 模拟错误errCh <- errors.New("worker 2 failed")return}results <- id * 10}(i)}go func() {wg.Wait()close(results)close(errCh)}()var err errorvar res []intfor {select {case r, ok := <-results:if !ok {results = nil} else {res = append(res, r)}case e := <-errCh:if e != nil && err == nil {err = e// 取消剩余任务return nil, err}}if results == nil {break}}return res, err
}func main() {res, err := parallelTasks()fmt.Println("Results:", res)fmt.Println("Error:", err)
}

六、生产级通道模式

6.1 背压控制实现

package mainimport ("fmt""time"
)type PressureAwareChannel struct {ch        chan intbackPress chan struct{}
}func NewPressureAwareChannel(size int) *PressureAwareChannel {return &PressureAwareChannel{ch:        make(chan int, size),backPress: make(chan struct{}, 1),}
}func (pac *PressureAwareChannel) Send(val int) bool {select {case pac.ch <- val:return truedefault:select {case pac.backPress <- struct{}{}:fmt.Println("Backpressure activated!")default:}return false}
}func main() {pac := NewPressureAwareChannel(3)// 生产者go func() {for i := 1; ; i++ {if !pac.Send(i) {time.Sleep(1 * time.Second)i-- // 重试}}}()// 消费者go func() {for {select {case val := <-pac.ch:fmt.Println("Consumed:", val)time.Sleep(2 * time.Second) // 慢消费case <-pac.backPress:fmt.Println("Processing backpressure...")}}}()select {} // 保持程序运行
}

七、调试与诊断

7.1 可视化通道状态

package mainimport ("fmt""reflect""time"
)func channelStatus(ch interface{}) string {c := reflect.ValueOf(ch)if c.Kind() != reflect.Chan {return "Not a channel"}// 获取通道状态state := "open"if c.IsClosed() {state = "closed"}// 获取缓冲区使用情况bufferUsage := ""if c.Cap() > 0 {length := c.Len()bufferUsage = fmt.Sprintf("buffer %d/%d", length, c.Cap())}return fmt.Sprintf("%s (%s)", state, bufferUsage)
}func main() {ch := make(chan int, 3)ch <- 1go func() {time.Sleep(2 * time.Second)close(ch)}()for i := 0; i < 5; i++ {fmt.Println("Channel status:", channelStatus(ch))time.Sleep(1 * time.Second)}
}

结语:通道设计哲学与最佳实践

  1. 通道所有权原则

    • 创建者负责关闭
    • 明确区分生产者和消费者角色
    • 不要在多处共享写通道
  2. 性能黄金法则

    • 无缓冲通道用于强同步场景
    • 缓冲通道大小根据处理时延设置
    • 批量处理提升吞吐量
  3. 错误处理三要素

    • 使用专用错误通道
    • 实现超时机制
    • 支持取消传播
  4. 生产环境要点

    // 安全关闭模式
    func SafeClose(ch chan int) (justClosed bool) {defer func() {if recover() != nil {justClosed = false}}()close(ch) // 如果ch已关闭会panicreturn true
    }// 安全发送模式
    func SafeSend(ch chan int, value int) (closed bool) {defer func() {if recover() != nil {closed = true}}()ch <- valuereturn false
    }
    

通过本文的完整示例和模式,开发者可以构建出健壮的并发系统。记住:通道不是银弹,但正确使用时,它们能帮助您编写出清晰、安全且高效的并发代码。

相关文章:

回顾Golang的Channel与Select第二篇

深入掌握Go Channel与Select&#xff1a;从原理到生产级实践 一、Channel基础&#xff1a;不只是数据管道 1.1 通道的完整生命周期&#xff08;可运行示例&#xff09; package mainimport ("fmt""time" )func main() {// 创建缓冲通道ch : make(chan i…...

基于mediapipe深度学习的手势数字识别系统python源码

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 程序运行配置环境&#xff1a; 人工智能算法python程序运行环境安装步骤整理-CSDN博客 3.部分核心…...

JS实现大文件切片上传以及断点续传

切片上传的原理是&#xff1a; 1.因为file对象的基类是blob&#xff0c;所以可以使用slice分割 2.将从input中获取的file对象使用slice进行分割&#xff0c;每5M一片 3.分别上传各个切片&#xff0c;等待切片上传完通知服务端合并&#xff08;或者传每一片时把切片总数量也传…...

AI编程01-生成前/后端接口对表-豆包(或Deepseek+WPS的AI

前言: 做过全栈的工程师知道,如果一个APP的项目分别是前端/后端两个团队开发的话,那么原型设计之后,通过接口文档进行开发对接是非常必要的。 传统的方法是,大家一起定义一个接口文档,然后,前端和后端的工程师进行为何,现在AI的时代,是不是通过AI能协助呢,显然可以…...

小众宝藏分子生物学实验中常用的软件:InSequence

欢迎使用InSequence&#xff0c;正版免费使用&#xff0c;操作友好&#xff0c;小白也能轻松上手哦~ 1. 全新中文界面与更大操作空间 全中文简洁直观的操作界面&#xff0c;常用功能固定至工具栏&#xff0c;随心自定义更改工具栏&#xff0c;让科研人员能够更快速地上手&…...

【自学笔记】机器学习基础知识点总览-持续更新

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 机器学习重点知识点总览一、机器学习基础概念二、机器学习理论基础三、机器学习算法1. 监督学习2. 无监督学习3. 强化学习 四、机器学习处理流程五、机器学习常见问…...

HCIA综合项目之多技术的综合应用实验

十五 HCIA综合实验 15.1 IP规划 #内网分配网段192.168.1.0 24#内网包括骨干链路和两个用户网段&#xff0c;素以需要划分三个&#xff0c;借两位就够用了192.168.1.0 26--骨干192.168.1.64 26---R1下网络192.168.1.128 26---R2下网络192.168.1.192 26--备用​192.168.1.64 26--…...

[免费]Springboot+Vue医疗(医院)挂号管理系统【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringbootVue医疗(医院)挂号管理系统&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue医疗(医院)挂号管理系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 在如今社会上&#xff0c;关于信息上…...

网络基础 【UDP、TCP】

1.UDP 首先我们学习UDP和TCP协议 要从这三个问题入手 1.报头和有效载荷如何分离、有效载荷如何交付给上一层的协议&#xff1f;2.认识报头3.学习该协议周边的问题 UDP报头 UDP我们先从示意图来讲解&#xff0c;认识报头。 UDP协议首部有16位源端口号&#xff0c;16位目的端…...

Linux centos8部署maven3.9.9

Linux环境为centos8 一、环境配置 下载部署maven之前先需要先部署好Java环境&#xff0c;我这里是Java17.0.6 先去官网下载jdk包&#xff0c;然后进行环境配置 vim /etc/profile 配置如下&#xff1a; export JAVA_HOME/root/jdk-17.0.6 #Java的安装目录 export JRE_HOM…...

谈谈云计算、DeepSeek和哪吒

我不会硬蹭热点&#xff0c;去分析自己不擅长的跨专业内容&#xff0c;本文谈DeepSeek和哪吒&#xff0c;都是以这两个热点为引子&#xff0c;最终仍然在分析的云计算。 这只是个散文随笔&#xff0c;没有严谨的上下游关联关系&#xff0c;想到哪里就写到哪里。 “人心中的成见…...

链表(典型算法思想)—— OJ例题算法解析思路

目录 一、2. 两数相加 - 力扣&#xff08;LeetCode&#xff09; 算法代码&#xff1a; 1. 初始化 2. 遍历链表并相加 3. 返回结果 举例说明 二、24. 两两交换链表中的节点 - 力扣&#xff08;LeetCode&#xff09; 算法代码&#xff1a; 代码思路 举例说明 初始状…...

【C++指南】解锁C++ STL:从入门到进阶的技术之旅

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《C指南》 期待您的关注 目录 一、STL 是什么 二、STL 的核心组件 2.1 容器&#xff08;Containers&#xff09; 2.2 算法&…...

LeetCode刷题---字符串---859

亲密字符串 859. 亲密字符串 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 给你两个字符串 s 和 goal &#xff0c;只要我们可以通过交换 s 中的两个字母得到与 goal 相等的结果&#xff0c;就返回 true &#xff1b;否则返回 false 。 交换字母的定义是&…...

数据处理中多线程功能的设计逻辑,及python的多线程实现

数据处理中多线程功能的设计逻辑主要是通过并发编程模型来提高程序的执行效率和响应速度。多线程允许在同一进程中创建多个线程&#xff0c;每个线程独立执行任务&#xff0c;同时共享进程的资源&#xff08;如内存空间&#xff09;。这种机制特别适用于I/O密集型任务&#xff…...

DeepSeek-R1技术革命:用强化学习重塑大语言模型的推理能力

引言&#xff1a;低成本高性能的AI新范式 在2025年1月&#xff0c;中国AI公司DeepSeek发布了两个标志性模型——DeepSeek-R1-Zero与DeepSeek-R1&#xff0c;以仅600万美元的训练成本实现了与OpenAI O1系列&#xff08;开发成本约5亿美元&#xff09;相当的推理性能&#xff0c…...

python中的深度学习框架TensorFlow 和 PyTorch 有什么区别?

TensorFlow 和 PyTorch 是目前最流行的两个深度学习框架,它们在设计理念、使用方式和社区支持等方面存在一些显著的区别。以下是它们的主要区别: 1. 设计理念 TensorFlow: 静态计算图:TensorFlow 使用静态计算图,即在运行模型之前需要先定义整个计算图。这使得 TensorFlo…...

用 Python 实现 DeepSeek R1 本地化部署

DeepSeek R1 以其出色的表现脱颖而出&#xff0c;不少朋友想将其本地化部署&#xff0c;网上基于 ollama 的部署方式有很多&#xff0c;但今天我要带你领略一种全新的方法 —— 使用 Python 实现 DeepSeek R1 本地化部署&#xff0c;让你轻松掌握&#xff0c;打造属于自己的 AI…...

Spreadjs与GcExcel

GcExcel VS SpreadJS 前言 报表系统前端化,释放后端压力,调高前端研发产能,但随着报表系统的数据量的增加,浏览器的限制,前端报表已达到瓶颈,用户使用体验逐渐不友好,为解决这一问题,找到新的解决方案,所以写下此篇对比 两者分别是什么? SpreadJS 是一款基于 HTML5…...

vue中使用lodash的debounce(防抖函数)

1、安装 npm i --save lodash.debounce2、引入 import debounce from lodash.debounce3、使用 <van-search v-model"searchValue" placeholder"输入姓名或工号" inputhandleInput />第一种&#xff1a; handleInput: debounce(function (val) {c…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...