• go 工作池配合消息队列


     

    工作池与消息队列框架

    Woker Pool:工作池中有固定数量的协程,每一个协程对应一个消息任务队列。

    消息任务队列:消息任务队列,本质就是go中的缓冲信道,任务在缓冲信道中传输,等待被处理。

    TaskQueue:消息任务队列的集合,本质就是

    client Handler Reader:在这里假设为客户端请求的处理方法,将请求对象或者任务传到某一个消息任务队列。

    clent Handler Writer:客户端返回响应的执行程序。

    简单工作池与消息队列的实现

    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
    }
    

     执行结果:

    写入字符 hello1
    接收字符 hello1
    写入字符 hello1
    接收字符 hello1
    写入字符 hello1
    接收字符 hello1
    写入字符 hello1
    接收字符 hello1
    写入字符 hello1
    接收字符 hello1
    写入字符 hello1
    接收字符 hello1
    写入字符 hello1
    接收字符 hello1
    。。。。。。

      

    Tcp服务器使用工作池与消息队列

    初始化

    初始化工作池对象,cap消息队列数量,前面说了,消息队列与work数量一致,也限制了工作池中协程的数量,tasksSize为每一个消息队列的最大容量,TaskQueue:make([]chan IConnection,cap)创建了消息队列的集合。

    func  NewWorkerPool(cap int,len int)*WorkerPool{
    	return &WorkerPool{
    		cap:cap,
    		tasksSize:len,
    		TaskQueue:make([]chan IConnection,cap),
    	}
    }

    启动工作池与消息队列

    每一个任务队列对应一个协程,在这里我们为每一个worker开辟了任务队列。

    //启动一个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
    		}
    	}
    }

    源码
    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),
    	}
    }
    

      

    
    
  • 相关阅读:
    1038 Recover the Smallest Number (30分) sort-cmp妙用(用于使字符串序列最小)
    1033 To Fill or Not to Fill (25分)贪心(???)
    1030 Travel Plan (30分) dij模板题
    1020 Tree Traversals (25分)(树的构造:后序+中序->层序)
    1022 Digital Library (30分) hash模拟
    1018 Public Bike Management (30分)(Dijkstra路径保存fa[]+DFS路径搜索)
    1017 Queueing at Bank (25分)模拟:关于事务排队处理
    1014 Waiting in Line (30分)队列模拟题
    1010 Radix (25分)暴力猜数or二分猜数
    HDU 3032 multi-sg 打表找规律
  • 原文地址:https://www.cnblogs.com/-wenli/p/12346963.html
Copyright © 2020-2023  润新知