[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 ...
随机推荐
- [TimLinux] Python Django myblog启动
1. myblog介绍 自己给自己定的一个学习项目,用于: 使用学到的Python Web开发技术,框架django 使用学到的CSS技术,实现前端功能 使用学到的Axure工具,画出前端页面功能草图 ...
- CodeForces 5C Longest Regular Backet sequence
This is yet another problem dealing with regular bracket sequences. We should remind you that a brac ...
- 【consul】使用学习
[consul]使用学习 转载:https://www.cnblogs.com/yangchongxing/p/10653791.html 1.下载 consul https://www.consul ...
- 【Visual Studio Code】插件
[Visual Studio Code]插件 转载:https://www.cnblogs.com/yangchongxing/p/10625628.html 目录 ================= ...
- 基于TCP协议之socket编程
#服务端 #导入一个socket模块 import socket #想象成买手机打电话:socket.SOCK_STREAM 表示建立tcp连接 ,udp连接socket.SOCK_DGRAM #买了 ...
- 《Java基础知识》Java变量的声明、初始化和作用域
一.Java变量的声明 在 Java 程序设计中,每个声明的变量都必须分配一个类型.声明一个变量时,应该先声明变量的类型,随后再声明变量的名字.下面演示了变量的声明方式. double salary; ...
- 《Java基础知识》Java内部类及其实例化
在 Java 中,允许在一个类(或方法.语句块)的内部定义另一个类,称为内部类(Inner Class),有时也称为嵌套类(Nested Class). 内部类和外层封装它的类之间存在逻辑上的所属关系 ...
- android开发针对小米、三星、华为8.0+系统个别型号打开应用闪退
最近开发中有个别客户反馈新换的三星.小米或者华为手机打开应用就闪退,而且是个别型号.针对这种情况特别查阅了一些资料,原因是8.0+系统的手机不允许后台创建服务,那么怎么修改呢,请看代码: 1.修改启动 ...
- 小米开源数据库<pegasus>简介
数据模型 组合键:Table + HashKey + SortKey Table实现业务数据的隔离 HashKey决定数据在那个分片 SortKey决定数据在分片内的排序 一致性协议 使用Pacifi ...
- 【Java必修课】好用的Arrays.asList也有这三个坑
好用的asList 在开发或写测试用例的过程中,经常会用到Arrays.asList()这个方法,可以快速方便地将数组转化成一个List.例如: List<String> list = A ...