当前位置: 首页 > article >正文

Golang倒腾一款简配的具有请求排队功能的并发受限服务器

图片

golang官方指南[1]给了一些代码片段,层层递进演示了信道的能力:

1>. 信号量
2>. 限流能力

var sem = make(chan int, MaxOutstanding) func Serve(queue chan *Request) {for req := range queue {req:= reqsem <- 1   go func() {   // 只会开启MaxOutstanding个并发协程process(req)<-sem}()}
}

上面出现了两个信道:

① sem 提供了限制服务端并发处理请求的信号量
② queue 提供了一个客户端请求队列,起媒介/解耦的作用


进一步指南给出了信道的另一个用法: 3>. 解多路复用

多路复用是网络编程中一个耳熟能详的概念,nginx redis等高性能web、内存kv都用到了这个技术 。

这个解多路复用是怎么理解呢?

离散/独立/并发的客户端请求被服务端Serve收敛之后, Serve就起到了多路复用的概念,在Request定义resultChan信道,就给每个客户端请求提供了独立获取请求结果的能力,这便是一种解多路复用。


从实际效果看这就是常见的互联网web服务器:一款具备请求排队功能的并发限流服务器

f09bb9cbd0a0799b91ce51dfd7c16b23.png

官方指南并没有完整实现客户端和服务器端工程。

下面是我的工程化实现, 记录实践中遇到的问题。

并发受限服务器

  • 信道queue接收客户端请求,解耦客户端和服务器,天然具备排队能力

  • 信号量信道sem提供了并发受限的能力

  • 服务器处理完,向解多路复用信道req.resultChan写入响应结果。

/* 实现一个有请求队列功能的并发请求受限服务器*/package mainimport ("fmt""sync""time"
)var sem = make(chan int, Maxoutstanding)var wg2 sync.WaitGroupfunc server(queue chan *Request) {fmt.Printf("Server is already, listen req \n")for req := range queue {req := reqsem <- 1wg2.Add(1)go func() {defer wg2.Done()process(req)<-sem}()}
}func process(req *Request) {s := sum(req.args)req.resultChan <- s
}
func sum(a []int) (s int) {for i := 1; i <= a[0]; i++ {s += i}time.Sleep(time.Millisecond * 20)return s
}

time.Sleep模拟服务器处理请求单次耗时20ms, 输出数字的累加,
eg: input: 100;
output: (1+100)/2*100 =5050

wg2 sync.WaitGroup是一个动态活跃的Goroutine计数器,注意用法和位置,wg2的作用是:等待所有请求处理完成。

并发客户端请求

for循环开启并发客户端请求,

  • 每个请求入驻一个独立的Goroutine,独立向信道queue投递请求和接收响应

package mainimport ("fmt""sync"
)type Request struct {args       []intresultChan chan int
}var wg1 sync.WaitGroupfunc clients() {fmt.Printf("start %d concurrency client request\n ", concurrencyClients)for i := 1; i <= concurrencyClients; i++ {r := &Request{args:       []int{i},resultChan: make(chan int),}wg1.Add(1)go ClientReq(r)}wg1.Wait() }func ClientReq(r *Request) {defer wg1.Done()queue <- rgo func() {res := <-r.resultChanfmt.Printf("current args is %d, the result is %d \n", r.args[0], res)}()
}

wg1 WaitGroup的目的是确保所有的客户端请求都已经发出,之后客户端任务结束,所以此处我们新开Goroutine处理响应结果(这里又有闭包的参与)。

工程化

工程化代码的先后顺序,决定了代码是否死锁。
server需要处于监听状态,故先启动。

本处clients在主协程整体上是同步发送,如果放在clients()的后面,clients内的wg1可能会有部分请求Goroutine阻塞在信道queue, 且没法唤醒, 运行时会检测出报死锁。

package mainimport ("fmt""time"
)var concurrencyClients = 1000
var queueLength = 100
var queue = make(chan *Request, queueLength) // 请求队列长度
var Maxoutstanding int = 10                  // 服务器并发受限10func main() {go server(queue)var start = time.Now()clients() // 确保所有的请求都已经发出去wg2.Wait() // 确保服务器处理完所有的请求fmt.Printf("客户端并发%d请求,服务器请求队列长度%d,服务器限流%d,总共耗时%d ms \n", concurrencyClients, queueLength, Maxoutstanding, time.Since(start).Milliseconds())
}

上面出现了3个配置变量
1>.  客户端并发请求数量concurrencyClients=100
2>.  服务器排队队列长度queueLength=100, 会作用到信道queue
3>.  服务器并发受限阈值Maxoutstanding=10

start 1000 concurrency client requestServer is already, listen req 
current args is 14, the result is 105 
current args is 2, the result is 3 
current args is 3, the result is 6 
current args is 1, the result is 1 
current args is 4, the result is 10 
current args is 8, the result is 36 
current args is 6, the result is 21 
current args is 12, the result is 78 
current args is 5, the result is 15 
current args is 7, the result is 28 
current args is 18, the result is 171 
current args is 16, the result is 136 
current args is 15, the result is 120 
current args is 20, the result is 210 
current args is 19, the result is 190 
current args is 13, the result is 91 
current args is 21, the result is 231 
current args is 10, the result is 55 
current args is 17, the result is 153 
current args is 9, the result is 45 
current args is 22, the result is 253 
current args is 28, the result is 406 
current args is 27, the result is 378 
current args is 11, the result is 66 
current args is 26, the result is 351 
current args is 30, the result is 465 
current args is 23, the result is 276 
current args is 25, the result is 325 
current args is 29, the result is 435 
current args is 24, the result is 300 
current args is 31, the result is 496 
current args is 34, the result is 595 
current args is 38, the result is 741 
current args is 36, the result is 666 
current args is 41, the result is 861 
current args is 32, the result is 528 
current args is 35, the result is 630 
current args is 33, the result is 561 
current args is 37, the result is 703 
current args is 39, the result is 780 
current args is 52, the result is 1378 
current args is 46, the result is 1081 
current args is 47, the result is 1128 
current args is 49, the result is 1225 
current args is 45, the result is 1035 
current args is 43, the result is 946 
current args is 48, the result is 1176 
current args is 40, the result is 820 
current args is 42, the result is 903 
current args is 44, the result is 990 
current args is 59, the result is 1770 
current args is 55, the result is 1540 
current args is 53, the result is 1431 
current args is 57, the result is 1653 
current args is 51, the result is 1326 
current args is 54, the result is 1485 
current args is 50, the result is 1275 
current args is 56, the result is 1596 
current args is 58, the result is 1711 
current args is 60, the result is 1830 
current args is 66, the result is 2211 
current args is 63, the result is 2016 
current args is 70, the result is 2485 
current args is 62, the result is 1953 
current args is 61, the result is 1891 
current args is 65, the result is 2145 
current args is 67, the result is 2278 
current args is 64, the result is 2080 
current args is 68, the result is 2346 
current args is 69, the result is 2415 
current args is 76, the result is 2926 
current args is 77, the result is 3003 
current args is 71, the result is 2556 
current args is 80, the result is 3240 
current args is 75, the result is 2850 
current args is 74, the result is 2775 
current args is 73, the result is 2701 
current args is 72, the result is 2628 
current args is 78, the result is 3081 
current args is 81, the result is 3321 
current args is 89, the result is 4005 
current args is 83, the result is 3486 
current args is 88, the result is 3916 
current args is 82, the result is 3403 
current args is 79, the result is 3160 
current args is 86, the result is 3741 
current args is 84, the result is 3570 
current args is 90, the result is 4095 
current args is 85, the result is 3655 
current args is 87, the result is 3828 
current args is 101, the result is 5151 
current args is 92, the result is 4278 
current args is 94, the result is 4465 
current args is 93, the result is 4371 
current args is 98, the result is 4851 
current args is 91, the result is 4186 
current args is 99, the result is 4950 
current args is 100, the result is 5050 
current args is 95, the result is 4560 
current args is 96, the result is 4656 
current args is 109, the result is 5995 
current args is 107, the result is 5778 
current args is 108, the result is 5886 
current args is 102, the result is 5253 
current args is 103, the result is 5356 
current args is 106, the result is 5671 
current args is 105, the result is 5565 
current args is 104, the result is 5460 
current args is 111, the result is 6216 
current args is 97, the result is 4753 
current args is 120, the result is 7260 
current args is 112, the result is 6328 
current args is 113, the result is 6441 
current args is 114, the result is 6555 
current args is 110, the result is 6105 
current args is 119, the result is 7140 
current args is 115, the result is 6670 
current args is 117, the result is 6903 
current args is 116, the result is 6786 
current args is 118, the result is 7021 
current args is 123, the result is 7626 
current args is 122, the result is 7503 
current args is 130, the result is 8515 
current args is 121, the result is 7381 
current args is 126, the result is 8001 
current args is 129, the result is 8385 
......
current args is 988, the result is 488566 
current args is 992, the result is 492528 
current args is 976, the result is 476776 
current args is 984, the result is 484620 
current args is 995, the result is 495510 
current args is 999, the result is 499500 
current args is 1000, the result is 500500 
current args is 990, the result is 490545 
客户端并发1000请求,服务器请求队列长度100,服务器限流10,总共耗时2099 ms

读者可以随意调整3个参数的大小,来感受服务器调参的魅力。

并发客户端请求数concurrencyClients

服务器请求队列queueLength

服务器限流阈值 Maxoutstanding

耗时ms

1000

100

10

2067

1000

100

50

454

1000

100

100

210

1000

300

10

2082

1000

500

10

2071

3000

100

10

6259

5000

500

10

10516

完整代码传送门[2]

That’s All,本文根据golang有关信道的指南, 实现了一个带有请求队列功能的并发受限服务器, 巩固了信道、WaitGroup的用法。

参考资料

[1] 

golang官方指南: https://go.dev/doc/effective_go

[2] 

完整代码传送门: https://github.com/zwbdzb/go_sample1

本篇文字和图片均为原创,读者可结合图片探索源码, 欢迎反馈 ~。。~。欢迎添加微信号 niumabujuan 交流撕逼。 

图片

一种基于etcd实践节点自动故障转移的思路

一次sql请求,返回分页数据和总条数

http请求超时,底层发生了什么?

两将军问题和TCP三次握手

字节二面:你怎么理解信道是Golang中的顶级公民

三张大图剖析HttpClient和IHttpClientFactory在DNS解析问题上的殊途同归

图片

点“图片戳“在看图片

相关文章:

Golang倒腾一款简配的具有请求排队功能的并发受限服务器

golang官方指南[1]给了一些代码片段&#xff0c;层层递进演示了信道的能力: 1>. 信号量2>. 限流能力 var sem make(chan int, MaxOutstanding) func Serve(queue chan *Request) {for req : range queue {req: reqsem <- 1 go func() { // 只会开启MaxOutstandin…...

【运维】服务器系统从centos7重装为ubuntu22.04

目录 一、硬盘准备二、系统安装三、安装基本系统组件四、挂载机械硬盘五、问题解决 一、硬盘准备 【注意&#xff1a;这一步会把硬盘的数据清空&#xff0c;所以需要找一个空的U盘或者把U盘数据备份】 ubuntu22.04下载 需要先安装 bittorrent 下载完之后会打开一个网页 然后…...

创新技术引领软件供应链安全,助力数字中国建设

编者按 随着数字化转型的加速&#xff0c;针对软件供应链的攻击事件呈快速增长态势&#xff0c;目前已成为网络空间安全的焦点。如何将安全嵌入到软件开发到运营的全流程&#xff0c;实现防护技术的自动化、一体化、智能化&#xff0c;成为技术领域追逐的热点。 悬镜安全作为…...

【设计模式】建造者模式——工厂模式

三、建造者模式——工厂模式 3.1 工厂模式 创建一个类对象的传统方式是使用关键字new, 因为用new 创建的类对象是一个堆对象&#xff0c;可以实现多态。工厂模式通过把创建对象的代码包装起来&#xff0c;实现创建对象的代码与具体 的业务逻辑代码相隔离的目的(将对象的创建和…...

Java基础:枚举类enum入门案例

1.基础枚举定义与使用&#xff1a; package com.zxy;public class Main {public static void main(String[] args) { // 获取枚举值cars car cars.BMW;switch (car){case BMW :System.out.println("BMW");break;case BENZ :System.out.println("BENZ&…...

蓝桥备赛(18)- 红黑树和 set 与 map(上)

对于二叉搜索树 &#xff0c; 平衡二叉树 &#xff0c; 以及红黑树 &#xff0c; 目前只需要了解背后的原理 &#xff0c; 不做代码实现的要求 &#xff0c; 重要的就是了解各种操作的时间复杂度即可 &#xff0c; 为set 与 map 做铺垫 一、二叉搜索树 1.1 基本概念 相较与于堆…...

Spring Boot集成EasyExcel

1. 初始化Spring Boot项目 首先&#xff0c;使用Spring Initializr&#xff08;https://start.spring.io/&#xff09;生成一个基本的Spring Boot项目。选择以下依赖项&#xff1a; Spring WebLombok (用于减少样板代码)SLF4J (用于日志记录) 2. 添加依赖 在你的pom.xml文件…...

obeaver 连接oracle 库 模式乱码

下载orai18n-12.1.0.2.0.jar 库--添加文件--把提前下载好的jar 随便放在一个文件夹下--添加文件选中&#xff0c;然后点击找到类&#xff0c; 选择类&#xff0c;确定即可正常 下载地址&#xff1a;https://download.csdn.net/download/weixin_42845364/88368302...

ChatGPT 使用教程:深度探索AI常用功能技巧

文章目录 前言一、ChatGPT介绍1.1 人工智能与自然语言处理的发展1.2 ChatGPT 的诞生与意义 二、ChatGPT 基础入门2.1 注册与登录2.2 对话界面介绍2.3 基本提问方式 三、常用功能详解3.1 文本生成3.2 问题回答3.3 语言翻译3.4 代码生成与调试 四、高级使用技巧4.1 指令优化4.2 多…...

無人機的應用程序有那些可以部署在linux server 系統

Dronecode Project&#xff1a;由 Linux Foundation 主導的開源項目&#xff0c;提供無人機航空操作系統和導航工具的開發框架&#xff0c;適合開發者使用。 DeepSeek-R1&#xff1a;這是一個人工智能模型&#xff0c;適用於無人機的數據處理和分析&#xff0c;支持在 Linux 系…...

[HUBUCTF 2022 新生赛]messy_traffic

下载附件 看到文件类型直接用wireshark打开&#xff0c;对MySQL协议进行追踪流&#xff0c;并没有什么发现&#xff0c;后面对NO.437发现有用信息&#xff0c;http追踪流 发现**system(‘cat passwd.txt’);**这里是在打开查看passwd.txt&#xff0c;密码是"SignUpForHUBU…...

铁人三项(第五赛区)_2018_rop题解

先启动靶机连接看看。 直接ls&#xff0c;就给我输出句话&#xff0c;看来不能直接拿flag。 那走下流程。 查下位数和其他信息&#xff1a; 可以看到是32位的包&#xff0c;开了NX&#xff0c;但没开其他保护。 用ida32打开looklook。 主函数就是个这&#xff0c;看到了弹出的…...

package.json 依赖包约束及快速删除node_modules

文章目录 一、package.json版本约束1、初始项目安装2. 已有 yarn.lock 文件的项目安装3. 特殊情况手动修改 package.json 版本&#xff1a;使用 yarn upgrade 命令&#xff1a; 二、快速删除node_modules三、depcheck 检测npm未使用的依赖 一、package.json版本约束 1、初始项…...

Compose 实践与探索六 —— 动画的流程控制与 Transition

1、Block 参数&#xff1a;监听每一帧 animateTo() 与 animateDecay() 中都有一个函数类型的 block 参数&#xff1a; suspend fun animateDecay(initialVelocity: T,animationSpec: DecayAnimationSpec<T>,block: (Animatable<T, V>.() -> Unit)? null): An…...

虚拟机Contos7为啥不能被本机电脑访问?

1.查看防火墙是否开启 systemctl status firewalld.service 2.如果防火墙关闭就可以直接被访问 3.如果防火墙打开了我们需要开放端口(下面为防火墙一系列指令) # 关闭防火墙 systemctl stop firewalld.service# 打开防火墙 systemctl start firewalld.service# 关闭开启自启…...

【21】单片机编程核心技巧:if语句逻辑与真假判断

【21】单片机编程核心技巧&#xff1a;if语句逻辑与真假判断 七律 条件分野 if语句判真假&#xff0c;括号条件定乾坤。 非零为真零为假&#xff0c;大括号内藏玄门。 省略虽简风险在&#xff0c;代码规范护本根。 单片逻辑由心控&#xff0c;条件分支自成文。 注释&#xf…...

Java 实现 Android ViewPager2 顶部导航:动态配置与高效加载指南

Java 实现&#xff1a;明确使用的编程语言。Android ViewPager2&#xff1a;技术栈和核心组件。顶部导航&#xff1a;功能点。动态配置与高效加载指南&#xff1a;突出动态配置的灵活性和性能优化的重点。 在 Android 中使用 Java 实现 ViewPager2 和 TabLayout 的顶部导航也是…...

Python :数据模型

一. 什么是数据模型&#xff1f; Python数据模型是Python对象系统的抽象&#xff0c;通过一组特殊方法​&#xff08;如__init__、__len__等&#xff09;和协议​&#xff08;如迭代协议、上下文管理协议&#xff09;&#xff0c;定义了对象如何与语言的内置功能&#xff08;如…...

idea超级AI插件,让 AI 为 Java 工程师

引言​ 用户可在界面中直接通过输入自然语言的形式描述接口的需求&#xff0c;系统通过输入的需求自动分析关键的功能点有哪些&#xff0c;并对不确定方案的需求提供多种选择&#xff0c;以及对需求上下文进行补充&#xff0c;用户修改确定需求后&#xff0c;系统会根据需求设…...

施磊老师c++笔记(五)

继承与多态-深入掌握oop语言最强大的机制 文章目录 继承与多态-深入掌握oop语言最强大的机制1.继承的基本意义2.派生类的构造过程3.重载,隐藏,覆盖4.虚函数, 静态绑定和动态绑定--面试重点5.虚析构函数--重点在于什么呢时候用6.再讨论虚函数和动态绑定7.理解多态到底是什么8.理…...

µCOS-III从入门到精通 第十四章(软件定时器)

参考教程&#xff1a;【正点原子】手把手教你学UCOS-III实时操作系统_哔哩哔哩_bilibili 一、软件定时器简介 1、定时器的概念与种类 &#xff08;1&#xff09;定时器的概念&#xff1a;从指定的时刻开始&#xff0c;经过一个指定时间&#xff0c;然后触发一个超时事件&…...

MySQL数据库复杂的增删改查操作

在前面的文章中&#xff0c;我们主要学习了数据库的基础知识以及基本的增删改查的操作。接下去将以一个比较实际的公司数据库为例子&#xff0c;进行讲解一些较为复杂且现时需求的例子。 基础知识&#xff1a; 一文清晰梳理Mysql 数据库基础知识_字段变动如何梳理清楚-CSDN博…...

KCD 北京站丨Volcano 邀您畅聊云原生智能调度技术与应用

AI与云原生技术正以前所未有的速度改变着我们的世界&#xff0c;而云原生技术则如同一座坚实的桥梁&#xff0c;连接着传统IT与现代化的数字世界。当AI与云原生相遇&#xff0c;它们相互赋能&#xff0c;相互促进&#xff0c;为开发者们打开了一个全新的技术宇宙。 3 月 15 日&…...

BLEU评估指标

一、介绍 用于评估模型生成的句子和实际句子差异的指标&#xff0c;取值在[0,1]&#xff0c;匹配度高就距离1近&#xff0c;反之距离0近。这个指标计算代价小&#xff0c;容易理解&#xff0c;与语言无关&#xff0c;与人类评价结果高度相关。 BLEU主要基于n-gram匹配&#x…...

高效自动化测试:打造Python+Requests+Pytest+Allure+YAML的接口测试框架

一、背景 在快节奏的开发周期中&#xff0c;如何确保接口质量&#xff1f;自动化测试是关键。通过构建标准化、可复用的测试框架&#xff0c;能显著提升测试效率与准确性&#xff0c;为项目质量保驾护航[1][7]。 二、目标 ✅ 核心目标&#xff1a; ● 实现快速、高效的接口测试…...

如何修复 Tauri 发布后程序运行时显示 `asset not found: index.html` 的问题

如何修复 Tauri 发布后程序运行时显示 asset not found: index.html 的问题 在使用 Tauri 发布应用程序时&#xff0c;如果运行时出现 asset not found: index.html 的错误&#xff0c;通常是因为 Tauri 无法找到或正确加载前端资源文件&#xff08;如 index.html&#xff09;…...

BSides Vancouver: 2018 (Workshop)

BSides Vancouver: 2018 (Workshop) 来自 <https://www.vulnhub.com/entry/bsides-vancouver-2018-workshop,231/> 1&#xff0c;将两台虚拟机网络连接都改为NAT模式 2&#xff0c;攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23…...

rStar论文精读

论文简介 论文标题&#xff1a;《Mutual reasoning makes smaller LLMs stronger problem-solvers》 论文地址&#xff1a;https://arxiv.org/abs/2408.06195 录用会议&#xff1a;ICLR2025 背景与挑战 挑战1&#xff1a;在SLM中平衡exploration与exploitation。一些方法有很…...

【动态规划】对局匹配 (分组线性DP)

题目详情 问题描述&#xff1a; 小明喜欢在一个围棋网站上找别人在线对弈。这个网站上所有注册用户都有一个积分&#xff0c;代表他的围棋水平。   小明发现网站的自动对局系统在匹配对手时&#xff0c;只会将积分差恰好是K的两名用户匹配在一起。如果两人分差小于或大于K…...

python 提取视频中的音频

在Python中提取视频中的音频&#xff0c;你可以使用moviepy库&#xff0c;这是一个非常强大且易于使用的库&#xff0c;专门用于视频编辑。以下是如何使用moviepy来提取视频中的音频的步骤&#xff1a; 安装moviepy 首先&#xff0c;你需要安装moviepy。你可以通过pip安装它&a…...