[Go]TCP服务中增加消息队列与工作池
之前的处理中每一个连接都会创建一个主groutine , 每个连接中的主groutine中创建出读groutine 和写groutine
每个连接处理业务再单独开出一个groutine ,这样如果有10万并发的连接 , 将会出现30万groutine ,其中读写占20万阻塞住的 , 不占用资源。处理业务的有10万groutine ,会不停的切换 , 比较占有CPU资源 , 现在把处理业务的groutine限制住 ,创建出一个工作池,里面存的是每个worker ,每个worker groutine去读取自己对应的channel ,这个channel是个有缓存的channel作为消息队列使用
package snet import (
"bufio"
"fmt"
"log"
"math/rand"
"net"
"time"
) type Conn struct {
IP string
Port uint32
TCPConn *net.TCPConn
MsgChan chan []byte
ExitChan chan bool
Closed bool
WorkerPool []chan []byte
WorkerPoolSize uint32
PreWorkerQueue uint32
} func NewConn(IP string, Port uint32, WorkerPoolSize uint32) *Conn {
s := &Conn{
IP: IP,
Port: Port,
MsgChan: make(chan []byte),
ExitChan: make(chan bool),
WorkerPool: make([]chan []byte, WorkerPoolSize),
WorkerPoolSize: WorkerPoolSize,
PreWorkerQueue: ,
}
return s
} func (c *Conn) Start() {
log.Printf("%s:%d start...\n", c.IP, c.Port)
go func() {
c.StartWorkerPool()
addr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", c.IP, c.Port))
if err != nil {
log.Println("resolve tcp addr err ", err)
return
}
listener, err := net.ListenTCP("tcp4", addr)
if err != nil {
log.Println("listen tcp err ", err)
return
}
var connid uint32
connid =
for {
conn, err := listener.AcceptTCP()
if err != nil {
log.Println("accept tcp err ", err)
continue
}
c.TCPConn = conn
go c.StartRead()
go c.StartWrite()
connid++
}
}()
select {}
}
func (c *Conn) StartRead() {
log.Println("read groutine is waiting")
defer c.Stop()
defer log.Println("read groutine exit")
reader := bufio.NewReader(c.TCPConn)
for {
lineBytes, err := reader.ReadBytes('\n')
if err != nil {
log.Println("startread read bytes error ", err)
break
}
len := len(lineBytes)
line := lineBytes[:len-]
log.Println("start read from client ", string(line))
if c.WorkerPoolSize>{
c.SendMsgToWorker(line)
}else{
go c.HandleMsg(line)
}
}
}
func (c *Conn) StartWrite() {
log.Println("write groutine is waiting")
defer log.Println("write groutine exit")
for {
select {
case data := <-c.MsgChan:
if _, err := c.TCPConn.Write(data); err != nil {
log.Println("startwrite conn write error ", err)
return
}
log.Println("start write from server ", string(data))
case <-c.ExitChan:
return
}
}
}
func (c *Conn) HandleMsg(data []byte) {
res := fmt.Sprintf("res:%s", string(data))
c.MsgChan <- []byte(res)
}
func (c *Conn) SendMsgToWorker(data []byte) {
rand.Seed(time.Now().UnixNano())
workerId := rand.Intn(int(c.WorkerPoolSize))
c.WorkerPool[workerId] <- data
}
func (c *Conn) StartWorkerPool() {
for i := ; i < int(c.WorkerPoolSize); i++ {
c.WorkerPool[i] = make(chan []byte, c.PreWorkerQueue)
go c.StartOneWorker(i, c.WorkerPool[i])
}
}
func (c *Conn) StartOneWorker(workerId int, queue chan []byte) {
log.Println("start one worker groutine is waiting:", workerId)
for {
select {
case data := <-queue:
c.HandleMsg(data)
log.Println("one worker groutine is finshed:", workerId)
}
}
}
func (c *Conn) Stop() {
if c.Closed {
return
}
c.Closed = true
c.ExitChan <- true c.TCPConn.Close()
close(c.ExitChan)
close(c.MsgChan)
}

[Go]TCP服务中增加消息队列与工作池的更多相关文章
- 工业物联网或系统集成中应用消息队列(ActiveMQ,C#的demo)的场景全面分析
1.[连载]<C#通讯(串口和网络)框架的设计与实现> 2.[开源]C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍 2.应用SuperIO(SIO)和开源跨平台物联网框 ...
- 消息服务MNS和消息队列ONS产品对比
消息服务MNS和消息队列ONS产品对比 MNS已经进过严格测试,已达到商业化的稳定性要求,其主要特点和适用场景 1.数据高可靠(10个9),对于数据可靠性敏感(要求消息数据不丢)的应用场景建议选择. ...
- C#中使用消息队列RabbitMQ
在C#中使用消息队列RabbitMQ 2014-10-27 14:41 by qy1141, 745 阅读, 2 评论, 收藏, 编辑 1.什么是RabbitMQ.详见 http://www.rabb ...
- WCF分布式开发步步为赢(13):WCF服务离线操作与消息队列MSMQ
之前曾经写过一个关于MSMQ消息队列的文章:WCF分布式开发必备知识(1):MSMQ消息队列 ,当时的目的也是用它来作为学习WCF 消息队列MSMQ编程的基础文章.在那篇文章里,我们详细介绍了MSMQ ...
- Handler机制中的消息队列
--> 学习自蘑菇街大佬 Handler机制可以看成是一个消息阻塞队列,当有消息时立即处理消息,没有消息时则阻塞.在Android系统中APP启动后很快进入死循环,不断读取MessageQueu ...
- GaussDB(DWS)中共享消息队列实现的三大功能
摘要:本文将详细介绍GaussDB(DWS)中共享消息队列的实现. 本文分享自华为云社区<GaussDB(DWS)CBB组件之共享消息队列介绍>,作者:疯狂朔朔. 1)共享消息队列是什么? ...
- 如何应用.NET中的消息队列服务
建立一个队列是应用MSMQ的第一步.您可以通过Windows计算机管理控制台中的消息队列选项完成这一操作,或者自己编程建立一个队列.列表A中的C#代码建立了一个新的私有MSMQ消息队列(如果不存在队列 ...
- JMS(Java消息服务)与消息队列ActiveMQ基本使用(一)
最近的项目中用到了mq,之前自己一直在码农一样的照葫芦画瓢.最近几天研究了下,把自己所有看下来的文档和了解总结一下. 一. 认识JMS 1.概述 对于JMS,百度百科,是这样介绍的:JMS即Java消 ...
- Linux服务搭之 - 消息队列(RabbitMQ)
本章主要目的是为了后续spring-cloud-bus做准备,讲述在Linux Centos7操作系统中搭建 RabbitMQ… - 什么是RabbitMQ RabbitMQ 是一个使用 Erlang ...
随机推荐
- 2017 CCPC秦皇岛 A题 A Ballon Robot
The 2017 China Collegiate Programming Contest Qinhuangdao Site is coming! There will be teams parti ...
- 详谈springboot启动类的@SpringBootApplication注解
前几天我们学会了如何创建springboot项目今天我们说一下他是怎么运行的为什么不需要我们再去编写繁重的配置文件的 @SpringBootApplication 首先我们看一下这个注解,他是用来标注 ...
- jvm调优、常用工具
ps -ef | grep java查出进程id jmap -heap ID 查出jvm配置信息 加入参数:打印Gc日志,分析 GC日志分析工具: GCeasy 降低minor gc 和 full g ...
- electron中JS报错:require is not defined的问题解决方法
Electron已经发布了6.0正式版,升级后发现原来能运行的代码报错提示require is not defined 解决办法: 修改创建BrowserWindow部分的相关代码,设置属性webPr ...
- 使用CleanWebpackPlugin插件报错原因:CleanWebpackPlugin is not a constructor
// webpack版本:4.32.2 // 抛错原写法 const CleanWebpackPlugin = require("clean-webpack-plugin"); . ...
- python基础知识第七篇(练习)
# a. 获取内容相同的元素列表 l1 = [11,22,33] l2 = [22,33,44] for l in l1: if l in l2: print(l) # b. 获取 l1 中有, l2 ...
- LeetCode刷题总结-树篇(下)
本文讲解有关树的习题中子树问题和新概念定义问题,也是有关树习题的最后一篇总结.前两篇请参考: LeetCode刷题总结-树篇(上) LeetCode刷题总结-树篇(中) 本文共收录9道题,7道中等题, ...
- c++-纯虚函数和抽象类
纯虚函数和抽象类 C面向接口编程和C多态 函数类型语法基础 函数指针做函数参数(回调函数)思想剖析 函数指针做函数参数两种用法(正向调用.反向调用) 纯虚函数 抽象类 抽象类基本概念 抽象类在多继承中 ...
- Docke部署nginx并配置nginx
一.在docker中下载nginx镜像 docker pull nginx 二.在宿主机中创建挂在目录 mkdir -p /data/nginx/{conf,conf.d,html,log} 三.在挂 ...
- redlock算法及其问题
背景 redlock算法是为了解决什么问题呢? 在单redis实例实现分布式锁时,可能会出现线程A设置完锁后,master挂掉,slave提升为master,因为异步复制的特性,线程A设置的锁丢失了, ...