go 工作池配合消息队列
工作池与消息队列框架
Woker Pool:工作池中有固定数量的协程,每一个协程对应一个消息任务队列。
消息任务队列:消息任务队列,本质就是go中的缓冲信道,任务在缓冲信道中传输,等待被处理。
TaskQueue:消息任务队列的集合,本质就是
client Handler Reader:在这里假设为客户端请求的处理方法,将请求对象或者任务传到某一个消息任务队列。
clent Handler Writer:客户端返回响应的执行程序。
简单工作池与消息队列的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | package main import ( "fmt" "time" ) //任务:大致思路,所有任务类都必须实现Task接口,所以用户需要创建task类 type ITask interface { write() reader() } type task struct { c string } func (t *task)write(){ fmt.Println( "写入字符" ,t.c) } func (t *task)reader(){ fmt.Println( "接收字符" ,t.c) } func Newtask(c string)*task { return &task{ c: c, } } //限制 //1.worker工作池的任务队列的最大值 //2.任务队列中任务的最大数量 //协程池 type WorkerPool struct { cap int //工作池中协程的数量 tasksSize int //任务队列中最大任务的容量 TaskQueue [] chan ITask //信道集合 } //启动一个worker工作池,开启工作池只能发生一次 func (W *WorkerPool)StartWorkPool(){ //根据任务队列的大小,分别开启worker,每个worker用go来承载,每一个worker对应一个任务队列 for i:=0;i<W.cap;i++{ //为每个worker开辟缓冲信道(任务队列) W.TaskQueue[i] = make( chan ITask,W.tasksSize) //启动worker,阻塞等待任务从channel中到来 go W.StartOneWorker(i,W.TaskQueue[i]) } } func (W *WorkerPool)StartOneWorker(id int,taskqueue chan ITask){ for { select { case request :=<- taskqueue: //如果有消息过来,则处理业务 request.write() request.reader() default : continue } } } func (W *WorkerPool)Put(task ITask){ W.TaskQueue[0] <- task } func New(cap int,len int)*WorkerPool{ return &WorkerPool{ cap:cap, tasksSize:len, TaskQueue:make([] chan ITask,cap), } } func main(){ b := make( chan bool) Pool := New(1,10) //创建工作池,池中只有一个协程,每个协程对应最大任务数为10个 go Pool.StartWorkPool() task1 :=Newtask( "hello1" ) //task2 :=Newtask("hello2") //task3 :=Newtask("hello3") //task4 :=Newtask("hello4") time.Sleep(time.Second) //第一种方法测试 //Pool.Put(task1) //Pool.Put(task2) //Pool.Put(task3) //Pool.Put(task4) //第二种方式测试 go func (){ for { Pool.Put(task1) time.Sleep(time.Second) } }() <-b } |
执行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 写入字符 hello1 接收字符 hello1 写入字符 hello1 接收字符 hello1 写入字符 hello1 接收字符 hello1 写入字符 hello1 接收字符 hello1 写入字符 hello1 接收字符 hello1 写入字符 hello1 接收字符 hello1 写入字符 hello1 接收字符 hello1<br>。。。。。。 |
Tcp服务器使用工作池与消息队列
初始化
初始化工作池对象,cap消息队列数量,前面说了,消息队列与work数量一致,也限制了工作池中协程的数量,tasksSize为每一个消息队列的最大容量,TaskQueue:make([]chan IConnection,cap)创建了消息队列的集合。
1 2 3 4 5 6 7 | func NewWorkerPool(cap int,len int)*WorkerPool{ return &WorkerPool{ cap:cap, tasksSize:len, TaskQueue:make([] chan IConnection,cap), } } |
启动工作池与消息队列
每一个任务队列对应一个协程,在这里我们为每一个worker开辟了任务队列。
1 2 3 4 5 6 7 8 9 10 11 | //启动一个worker工作池,开启工作池只能发生一次 func (W *WorkerPool)StartWorkPool(){ //根据任务队列的大小,分别开启worker,每个worker用go来承载,每一个worker对应一个任务队列 for i:=0;i<W.cap;i++{ //为每个worker开辟缓冲信道(任务队列) W.TaskQueue[i] = make( chan IConnection,W.tasksSize) //启动worker,阻塞等待任务从channel中到来 go W.StartOneWorker(i,W.TaskQueue[i]) } } |
等待任务执行
1 2 3 4 5 6 7 8 9 10 11 12 | func (W *WorkerPool)StartOneWorker(id int,taskqueue chan IConnection){ for { select { case request :=<- taskqueue: //如果有消息过来,则处理业务 request.Start() default : continue } } } |
1 | <strong><br>源码</strong> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | package znet //限制 //1.worker工作池的任务队列的最大值 //2.任务队列中任务的最大数量 //协程池 type WorkerPool struct { cap int tasksSize int TaskQueue [] chan IConnection //信道集合 } //启动一个worker工作池,开启工作池只能发生一次 func (W *WorkerPool)StartWorkPool(){ //根据任务队列的大小,分别开启worker,每个worker用go来承载,每一个worker对应一个任务队列 for i:=0;i<W.cap;i++{ //为每个worker开辟缓冲信道(任务队列) W.TaskQueue[i] = make( chan IConnection,W.tasksSize) //启动worker,阻塞等待任务从channel中到来 go W.StartOneWorker(i,W.TaskQueue[i]) } } func (W *WorkerPool)StartOneWorker(id int,taskqueue chan IConnection){ for { select { case request :=<- taskqueue: //如果有消息过来,则处理业务 request.Start() default : continue } } } //将任务公平的分发,使用取模(客户端链接与工作池的协程数) func (W *WorkerPool)Put(Connection IConnection){ index := Connection.GetConnID()%uint32(W.cap) W.TaskQueue[index] <- Connection } func NewWorkerPool(cap int,len int)*WorkerPool{ return &WorkerPool{ cap:cap, tasksSize:len, TaskQueue:make([] chan IConnection,cap), } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
2019-02-22 Django之Models(一)