Talk Is Cheap,Show Me The Code-GoLang动态监听chan

详解如何在Golang中监听多个channel 这篇文章主要为大家详细介绍了如何在Golang中实现监听多个channel,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下。 阅读详情

Talk Is Cheap ,Show Me The Code

通常而言,监听chan的做法为(忽略退出条件,以及close情况:))

生产消费模型:
func TestForSelect(t *testing.T) {
	c := make(chan int)
	go func() {
		for {
			select {
			case v := <-c:
				fmt.Println(v)
			}
		}
	}()
	go func() {
		for {
			time.Sleep(time.Second)
			c <- 1
		}
	}()
	select {}
}

当有另外一个chan b的时候,当然可以照木照样的抄一遍,也可以如下,合并到一起:

c := make(chan int)
	c2 := make(chan int)
	go func() {
		for {
			select {
			case v := <-c:
				fmt.Println(v)
			case v2 := <-c2:
				fmt.Println(v2)
			}
		}
	}()
	go func() {
		for {
			time.Sleep(time.Second)
			c <- 1
			c2 <- 2
		}
	}()
	select {}

问题

  • 管理问题:在编码阶段,我们可以是确定有哪些是固定的internalChan,可以合并到一起,也可以单独一个goroutine ,但是随着程序的运行必然会有golang 提倡的通信机制而自定义chan,那么,这么多的chan ,能否都统一归并到一起,尤其对于生命周期等同于整个程序的动态chan的时候
  • 性能问题:性能问题基本涉及到的就是空间和时间问题,
    • 当用空间换时间: 既一个chan 一个goroutine的时候,golang 的MPG模型,终归会还是回到os Thread上,并且虽然goroutine是用户态概念(2k),但是,这并不能代表,可以随意的创建 ,当 chan 数量上升时,并不能保证程序有最好的吞吐量
    • 当时间换空间: 既n个chan 合并到一个goroutine的时候,当数量上升时,吞吐量不一定就会比goroutine低(原因: 因为MPG模型,真正的调用还是得靠kernal Thread)

性能问题

  • goroutine模式

    • 既一个chan 一个goroutine

    • func goroutine(chans ...<-chan int) <-chan int {
      	r := make(chan int, 1)
      	wg := sync.WaitGroup{}
      	wg.Add(len(chans))
      	go func() {
      		for i := 0; i < len(chans); i++ {
      			go func(index int) {
      				defer wg.Done()
      				for v := range chans[index] {
      					r <- v
      				}
      			}(i)
      		}
      		wg.Wait()
      		close(r)
      	}()
      	return r
      }
      
  • goroutineMerge模式

    • 既将routine进行合并输出

    • func mergeN(chans ...<-chan int) <-chan int {
      	r := make(chan int, 1)
      	go func() {
      		wg := sync.WaitGroup{}
      		wg.Add(len(chans))
      		for _, c := range chans {
      			go func(c <-chan int) {
      				for v := range c {
      					r <- v
      				}
      				wg.Done()
      			}(c)
      		}
      		wg.Wait()
      		close(r)
      	}()
      
      	return r
      }
      
    • 在这里插入图片描述

  • 反射reflect 模式

    • 既通过golang 底层的反射进行数据监听

    • func mergeReflect(chans ...<-chan int) <-chan int {
      	out := make(chan int)
      	go func() {
      		defer close(out)
      		var cases []reflect.SelectCase
      		for _, c := range chans {
      			cases = append(cases, reflect.SelectCase{
      				Dir:  reflect.SelectRecv,
      				Chan: reflect.ValueOf(c),
      			})
      		}
      
      		for len(cases) > 0 {
      			i, v, ok := reflect.Select(cases)
      			if !ok {
      				cases = append(cases[:i], cases[i+1:]...)
      				continue
      			}
      			out <- v.Interface().(int)
      		}
      	}()
      	return out
      }
      
  • selectn 模式

    • 既for select 模式,不同的是,内部为多个chan,篇幅太长,请看下面的github链接
  • Talk Is Cheap,Show Me The Code

  • 附上benchmark的结果:

BenchmarkMerge/goroutines/1-8         	   86295	     13567 ns/op	     128 B/op	       2 allocs/op
BenchmarkMerge/goroutines/2-8         	   72342	     16708 ns/op	     129 B/op	       2 allocs/op
BenchmarkMerge/goroutines/4-8         	   44443	     26431 ns/op	     130 B/op	       2 allocs/op
BenchmarkMerge/goroutines/8-8         	   22413	     53346 ns/op	     133 B/op	       2 allocs/op
BenchmarkMerge/goroutines/16-8        	   11371	    106253 ns/op	     137 B/op	       2 allocs/op
BenchmarkMerge/goroutines/32-8        	    5449	    191332 ns/op	     150 B/op	       2 allocs/op
BenchmarkMerge/goroutines/64-8        	    3517	    363736 ns/op	     173 B/op	       2 allocs/op
BenchmarkMerge/goroutines/128-8       	    1489	    700969 ns/op	     270 B/op	       3 allocs/op
BenchmarkMerge/goroutines/256-8       	     865	   1386511 ns/op	     574 B/op	       6 allocs/op
BenchmarkMerge/goroutines/512-8       	     441	   2698255 ns/op	    1703 B/op	      18 allocs/op
BenchmarkMerge/goroutines/1024-8      	     210	   5688581 ns/op	    7626 B/op	      80 allocs/op
BenchmarkMerge/goroutines/2048-8      	      90	  12348973 ns/op	   36526 B/op	     378 allocs/op
BenchmarkMerge/goroutines/4096-8      	      44	  24618458 ns/op	   75359 B/op	     782 allocs/op
BenchmarkMerge/goroutineMerge/1-8     	  109533	     12741 ns/op	     128 B/op	       2 allocs/op
BenchmarkMerge/goroutineMerge/2-8     	   73844	     17012 ns/op	     129 B/op	       2 allocs/op
BenchmarkMerge/goroutineMerge/4-8     	   44526	     27054 ns/op	     130 B/op	       2 allocs/op
BenchmarkMerge/goroutineMerge/8-8     	   22270	     53264 ns/op	     133 B/op	       2 allocs/op
BenchmarkMerge/goroutineMerge/16-8    	   10000	    105712 ns/op	     139 B/op	       2 allocs/op
BenchmarkMerge/goroutineMerge/32-8    	    5514	    199118 ns/op	     148 B/op	       2 allocs/op
BenchmarkMerge/goroutineMerge/64-8    	    3096	    371435 ns/op	     158 B/op	       2 allocs/op
BenchmarkMerge/goroutineMerge/128-8   	    1798	    673136 ns/op	     245 B/op	       3 allocs/op
BenchmarkMerge/goroutineMerge/256-8   	     888	   1336941 ns/op	     521 B/op	       6 allocs/op
BenchmarkMerge/goroutineMerge/512-8   	     440	   2759375 ns/op	    1380 B/op	      15 allocs/op
BenchmarkMerge/goroutineMerge/1024-8  	     210	   5810853 ns/op	    5734 B/op	      60 allocs/op
BenchmarkMerge/goroutineMerge/2048-8  	      84	  12583786 ns/op	   19938 B/op	     208 allocs/op
BenchmarkMerge/goroutineMerge/4096-8  	      48	  25377268 ns/op	   76672 B/op	     799 allocs/op
BenchmarkMerge/reflection/1-8         	   62776	     31075 ns/op	     613 B/op	      46 allocs/op
BenchmarkMerge/reflection/2-8         	   29730	     37526 ns/op	    1778 B/op	     110 allocs/op
BenchmarkMerge/reflection/4-8         	   17108	     73674 ns/op	    6210 B/op	     293 allocs/op
BenchmarkMerge/reflection/8-8         	    5742	    192402 ns/op	   41349 B/op	     951 allocs/op
BenchmarkMerge/reflection/16-8        	    2185	    502843 ns/op	  163921 B/op	    3084 allocs/op
BenchmarkMerge/reflection/32-8        	     628	   1721796 ns/op	  653066 B/op	   10842 allocs/op
BenchmarkMerge/reflection/64-8        	     207	   5746011 ns/op	 2611283 B/op	   40417 allocs/op
BenchmarkMerge/reflection/128-8       	      45	  22606500 ns/op	10467497 B/op	  155855 allocs/op
BenchmarkMerge/reflection/256-8       	      12	  89188162 ns/op	41944716 B/op	  613093 allocs/op
BenchmarkMerge/reflection/512-8       	       3	 363011605 ns/op	167168538 B/op	 2421282 allocs/op
BenchmarkMerge/reflection/1024-8      	       1	1541255668 ns/op	668969352 B/op	 9673817 allocs/op
BenchmarkMerge/reflection/2048-8      	       1	6367310291 ns/op	2679574976 B/op	38507950 allocs/op
BenchmarkMerge/reflection/4096-8      	       1	27469170016 ns/op	10684780424 B/op	154077029 allocs/op
BenchmarkMerge/selectn/1-8            	  102465	     15167 ns/op	     120 B/op	       3 allocs/op
BenchmarkMerge/selectn/2-8            	   44065	     27441 ns/op	     112 B/op	       2 allocs/op
BenchmarkMerge/selectn/4-8            	   16956	     71150 ns/op	     113 B/op	       2 allocs/op
BenchmarkMerge/selectn/8-8            	   10000	    193766 ns/op	     115 B/op	       2 allocs/op
BenchmarkMerge/selectn/16-8           	    3488	    542824 ns/op	     119 B/op	       2 allocs/op
BenchmarkMerge/selectn/32-8           	    2762	    433152 ns/op	     118 B/op	       2 allocs/op
BenchmarkMerge/selectn/64-8           	     975	   1368257 ns/op	     123 B/op	       2 allocs/op
BenchmarkMerge/selectn/128-8          	     654	   1747111 ns/op	     130 B/op	       2 allocs/op
BenchmarkMerge/selectn/256-8          	     433	   2708657 ns/op	     260 B/op	       3 allocs/op
BenchmarkMerge/selectn/512-8          	     304	   3865518 ns/op	     350 B/op	       4 allocs/op
BenchmarkMerge/selectn/1024-8         	     178	   6767176 ns/op	     573 B/op	       6 allocs/op
BenchmarkMerge/selectn/2048-8         	      96	  12775303 ns/op	    1932 B/op	      20 allocs/op
BenchmarkMerge/selectn/4096-8         	      49	  25543083 ns/op	    4819 B/op	      51 allocs/op

在这里插入图片描述

解决方案

  • 管理问题:
    • 采取统一的管理器,管理所有的channel
    • 当channel结束之后,自动进行复用
  • 性能问题
    • 自动提供升级和回滚策略,既当chan 达到某个数量时,自动升级(goroutine=>reflect=>selectn的形式),回滚同理
goevent:goevent 是由 golang 编写的事件调度器 活动 goevent 是由 golang 编写的事件调度器。 例子 监听事件 e := goevent . New () e . On ( func ( i int , s string ){ fmt . Printf ( "%d: %s \n " , i , s ) }) 扳机 e . Trigger ( 1 , "foo" ) 使用事件表 table := goevent . NewTable () table . On ( "foo" , func ( i int ){ fmt . Printf ( "foo: %d \n " , i ) }) table . On ( "bar" , func ( s string ){ fmt . Printf ( "bar: %s \n " , s ) }) table . Trigger ( "foo" , 1 ) tabl 立即下载

相关推荐

Windows 10下用VS2022编译AFSIM 2.9.0的完整避坑指南

本文提供了在Windows 10系统下,使用Visual Studio 2022编译AFSIM 2.9.0仿真框架的详细指南。文章系统梳理了从环境准备、CMake配置、编译链接到安装打包的全流程,并重点针对编译过程中常见的文件编码、命名空间冲突等高频错误提供了具体解决方案,旨在帮助开发者高效避坑,顺利完成AFSIM在Windows平台上的构建。

weixin_28839549的博客 549

[golang] go中如何监听一组channels

go中如何监听一组channels reflect.Select func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) cases := make([]reflect.SelectCase, len(chans)) for i, ch := range chans { cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.Valu

靑い空゛ 1134

实用工具系列 - Xshell安装下载与使用

一、介绍 二、下载 三、安装 四、使用

Passerby_Wang的博客 1万+

如何监听N个通道

如何监听未知个数的通道

weixin_43882879的博客 450

别再为CAD和GIS数据对不上而头疼了!一份完整的ArcGIS for AutoCAD坐标系定义与数据套合指南

本文详细介绍了如何通过ArcGIS for AutoCAD插件解决CAD与GIS数据坐标系不匹配的问题,实现数据的精准套合。文章从坐标系冲突分析、插件核心功能解析到五步标准化工作流,提供了完整的解决方案,帮助工程师和设计师提升跨平台协作效率。

weixin_42531886的博客 216

DeepSeek+Dify实战:零代码构建智能SQL生成器

本文详细介绍了如何利用DeepSeek和Dify零代码构建智能SQL生成器,帮助非技术人员通过自然语言查询数据库。文章涵盖从数据准备、知识库设计到Agent配置的全流程,并提供了优化技巧和实际应用案例,显著提升团队数据查询效率。

weixin_29311017的博客 418

浅谈Golang通道channel

浅谈Golang channel前言代码底层实现两个有趣的例子 前言 channel用于Goroutine间通信时的注意点 - 合理设置channel的size大小 / 正确地关闭channel 合理地运用channel的发送与接收 - 运用函数传入参数的定义,限制 <- chan 和 chan <- channel的底层实现 - 环形队列+发送、接收的waiter通知,结合goroutine的调度思考 理解并运用channel的阻塞逻辑 - 理解channel的每一对 收与发 之间的逻辑,巧

清风 1102

ESP-01S获取网络时间踩坑全记录:AT指令调试、JSON解析乱码、时区处理,一个都不能少

本文详细记录了使用ESP-01S WIFI模块获取网络时间的完整过程,包括AT指令调试、JSON解析乱码处理以及时区转换等关键步骤。通过实战案例和代码示例,帮助开发者避开常见陷阱,实现稳定的网络时间同步功能。

weixin_30460489的博客 295

golang实现监听者模式

监听者模式的作用是在对象之间定义一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。在代码中,被监听者接口定义了添加、删除和通知监听者的方法,而监听者接口定义了更新方法。

csdn_8023的博客 939

智能织梦:基于Rokid AR眼镜的家庭情感记忆增强系统设计与实践

本文介绍了基于Rokid AR眼镜的'智能织梦'系统,通过增强现实技术捕捉和重现家庭情感记忆。系统利用多模态传感器和轻量级情感识别模型,自动记录家庭互动中的情感峰值时刻,并生成沉浸式记忆片段。测试数据显示,该系统显著提升了家庭情感互动的频率和质量,特别适用于多代同堂家庭和记忆唤醒场景。

sre5engineer的博客 536

RK3588开发笔记-ES8311音频芯片调试记录

本篇博客主要记录如何在RK3588平台试ES8311音频芯片的过程。这包括硬件连接、内核配置、驱动程序调试和测试步骤。通过以上步骤,我们成功在RK3588平台上调试了ES8311音频芯片。这包括硬件连接、内核配置、设备树配置、驱动加载以及音频测试。希望这篇调试记录能为其他开发者提供一些帮助。如果你有任何问题或建议,欢迎留言讨上调论。

flypig has a dream! 3161

go语言实现一个监听器模式

请注意,这只是一个简单的示例,实际中可能需要更复杂的设计,特别是在多并发场景下需要考虑并发安全性。此外,Go 中还有其他方式实现观察者模式,比如使用。在 Go 中,可以使用接口和通道实现一个简单的监听器(Observer)模式。函数中,我们创建了事件源和两个具体的监听器,然后将监听器添加到事件源,并通过事件源通知所有监听器。在这个示例中,我们定义了。接口定义了监听器的行为,

servepeople的博客 487

YOLO11改进|注意力机制篇|引入MLCA轻量级注意力机制

YOLO11中添加MLCA轻量级注意力机制

A1983Z的博客 4054

[开源]Goravel,一个功能完备、具有良好扩展能力的 Golang Web 应用程序框架,致敬 Laravel

Goravel 是一个功能完备、具有良好扩展能力的 Web 应用程序框架。 作为一个起始脚手架帮助 Golang 开发者快速构建自己的应用。

韩同学的简单逻辑 1188

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

程序内部发布监听事件golang实现

简介 这是一个开源的用于golang程序内部发布和监听事件的package,其原理是通过定义一个全局变量存储监听的事件id和对应的handle函数,当发布事件时,通过事件id查找对应的handle,如果找到则执行该handle函数。 使用说明 安装 go get github.com/jageros/eventhub 使用 监听事件 seq := eventhub.Subscribe(eve...

jager's blog 2890

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

GO监听退出信号

package main import ( "fmt" "os" "os/signal" "syscall" ) func main() { sigs := make(chan os.Signal,1) done := make(chan bool,1) signal.Notify(sigs...

不求前途凶吉,但求落幕无悔! 2345

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

go动态创建/增加channel并处理数据

golang动态增加channel

游走在世界的边缘~ 962

深入理解 go chan

go 里面通过chan来实现协程之间的通信,chan大概就是一个协程给另一个协程发送信息的代理。多线程程序执行的时候,因为有 CPU 缓存,然后需要对同一块内存进行并发读写,可能会导致数据竞争的问题。在很多语言中,都提供了锁的机制,来保护一片内存同一时刻只能一个线程操作,比如 java 里面的关键字。go 里面很多情况下,在不同协程之间通信都是使用chan来实现的。进程会有阻塞态、运行态,go 里面的协程也有阻塞的状态,当需要的资源得不到满足的时候就会陷入阻塞。比如等待别的协程往chan。

rubys007的博客 3209

golang 监听端口网络流量

如果你使用我的包(github.com/oswaldoooo/cmicro)中的posix共享内存操作,并且你运行代码的系统是macos或者freebsd,创建posix共享内存时可能会报错,别着急,你只需要将我的包拉到本地,将sys/unix.go中Shm_Open函数中shm_open替换为open(macos和freebsd缺少/dev/shm目录)

A_super_C的博客 1047

golang 线程与通道

golang的线程和通道

begeneral的专栏 6005

golang基础-chan的select操作、定时器操作、超时控制、goroutine中使用recover

chan的只读和只写 a.只读chan的声明 Var 变量的名字 Var readChan b. 只写chan的声明 Var 变量的名字 chan Var writeChan chan chan的select操作 格式如下 Select { case u := <- ch1: case e := <- ch2: default: } 看实例

全干工程师 6791

[Go]select监听channel

[Go]select监听channel

lakdlfkasdf的博客 456

go使用chan的几个场合

go中chan有两个概念,无缓冲和有缓冲,定义如下: 遇到的问题1: 问题描述:有一些场合要并行处理,但是在并行处理的过程中,需要通过某些返回值来判断协程是否结束。 比如:使用ffmpeg处理视频的过程中,需要一边下载视频并将下载的视频截帧,并同时将截取的图片帧用作其他处理,这两者要并行处理。并且在下载视频,截取图片帧的同时,还要同时起另外一个协程处理相关的音频操作 解决办法:使用ch...

宁静致远的博客 7397

golang入门笔记——Hertz

Hertz是字节跳动研发的企业级微服务HTTP框架,具有高易用性、易扩展、低时延等特点。是基于自研网络库Netpoll开发的内部框架Hertz。Hertz框架整体上满足:1.极致性能优化的问题性2.面对未来不可控需求的扩展能力,Hertz采用了4层分层设计(应用层、路由层、协议层、传输层),保证各个层级功能内聚,同时通过层级之间的接口达到灵活扩展的目标。

qq_43716830的博客 5174

【Golang】TCP编程-学习笔记

Golang的主要设计目标之一就是面向大规模后端服务程序,网络通信这块是服务端程序必不可少也是至关重要的一部分。

QMxnbbb 1110

golang--监听文件夹内容变化

fsnotify库 安装 go get github.com/fsnotify/fsnotify import ( "bytes" "compress/gzip" "encoding/json" "fmt" "github.com/fsnotify/fsnotify" "io/ioutil" "log" "os" "strings" "time" ) func ListenFolderNew() { fmt.Print("-----文件夹监听-------") watcher,

IT艺术家-rookie的博客 2307
上一篇: Golang 锁源码分析
下一篇: 源码分析-Golang Chan
Coder_Joker
博客等级 码龄8年 39粉丝 67原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值