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

1>. 信号量

2>. 限流能力

var sem = make(chan int, MaxOutstanding) 

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

上面出现了两个信道:

sem 提供了限制服务端并发处理请求的信号量

queue 提供了一个客户端请求队列,起媒介/解耦的作用


进一步指南给出了信道的另一个用法:

3>. 解多路复用

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

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

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


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

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

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

并发受限服务器

  • 信道queue接收客户端请求,解耦客户端和服务器,天然具备排队能力
  • 信号量信道sem提供了并发受限的能力
  • 服务器处理完,向解多路复用信道req.resultChan写入响应结果。
/* 实现一个有请求队列功能的并发请求受限服务器*/

package main

import (
"fmt"
"sync"
"time"
) var sem = make(chan int, Maxoutstanding) var wg2 sync.WaitGroup func server(queue chan *Request) {
fmt.Printf("Server is already, listen req \n") for req := range queue {
req := req
sem <- 1 wg2.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 main

import (
"fmt"
"sync"
) type Request struct {
args []int
resultChan chan int
} var wg1 sync.WaitGroup func 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 <- r
go func() {
res := <-r.resultChan
fmt.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 main

import (
"fmt"
"time"
) var concurrencyClients = 1000
var queueLength = 100
var queue = make(chan *Request, queueLength) // 请求队列长度
var Maxoutstanding int = 10 // 服务器并发受限10 func 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, 会作用到信道queue=50

3>. 服务器并发受限阈值Maxoutstanding=10

start 1000 concurrency client request
Server 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 128, the result is 8256
current args is 124, the result is 7750
current args is 125, the result is 7875
current args is 127, the result is 8128
current args is 133, the result is 8911
current args is 135, the result is 9180
current args is 139, the result is 9730
current args is 137, the result is 9453
current args is 141, the result is 10011
current args is 131, the result is 8646
current args is 134, the result is 9045
current args is 138, the result is 9591
current args is 132, the result is 8778
current args is 136, the result is 9316
current args is 148, the result is 11026
current args is 142, the result is 10153
current args is 149, the result is 11175
current args is 147, the result is 10878
current args is 140, the result is 9870
current args is 150, the result is 11325
current args is 145, the result is 10585
current args is 146, the result is 10731
current args is 144, the result is 10440
current args is 143, the result is 10296
current args is 156, the result is 12246
current args is 155, the result is 12090
current args is 161, the result is 13041
current args is 157, the result is 12403
current args is 153, the result is 11781
current args is 151, the result is 11476
current args is 159, the result is 12720
current args is 154, the result is 11935
current args is 152, the result is 11628
current args is 158, the result is 12561
current args is 170, the result is 14535
current args is 164, the result is 13530
current args is 166, the result is 13861
current args is 160, the result is 12880
current args is 162, the result is 13203
current args is 167, the result is 14028
current args is 163, the result is 13366
current args is 169, the result is 14365
current args is 168, the result is 14196
current args is 165, the result is 13695
current args is 176, the result is 15576
current args is 179, the result is 16110
current args is 178, the result is 15931
current args is 174, the result is 15225
current args is 173, the result is 15051
current args is 172, the result is 14878
current args is 177, the result is 15753
current args is 171, the result is 14706
current args is 180, the result is 16290
current args is 175, the result is 15400
current args is 181, the result is 16471
current args is 193, the result is 18721
current args is 182, the result is 16653
current args is 184, the result is 17020
current args is 187, the result is 17578
current args is 186, the result is 17391
current args is 189, the result is 17955
current args is 183, the result is 16836
current args is 188, the result is 17766
current args is 185, the result is 17205
current args is 198, the result is 19701
current args is 195, the result is 19110
current args is 199, the result is 19900
current args is 190, the result is 18145
current args is 196, the result is 19306
current args is 192, the result is 18528
current args is 191, the result is 18336
current args is 205, the result is 21115
current args is 194, the result is 18915
current args is 197, the result is 19503
current args is 207, the result is 21528
current args is 210, the result is 22155
current args is 200, the result is 20100
current args is 213, the result is 22791
current args is 202, the result is 20503 ...... current args is 981, the result is 481671
current args is 978, the result is 478731
current args is 982, the result is 482653
current args is 970, the result is 470935
current args is 979, the result is 479710
current args is 980, the result is 480690
current args is 983, the result is 483636
current args is 989, the result is 489555
current args is 986, the result is 486591
current args is 987, the result is 487578
current args is 985, the result is 485605
current args is 977, the result is 477753
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

完整代码传送门

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

golang倒腾一款简配的具有请求排队功能的并发受限服务器的更多相关文章

  1. C#不用union,而是有更好的方式实现 .net自定义错误页面实现 .net自定义错误页面实现升级篇 .net捕捉全局未处理异常的3种方式 一款很不错的FLASH时种插件 关于c#中委托使用小结 WEB网站常见受攻击方式及解决办法 判断URL是否存在 提升高并发量服务器性能解决思路

    C#不用union,而是有更好的方式实现   用过C/C++的人都知道有个union,特别好用,似乎char数组到short,int,float等的转换无所不能,也确实是能,并且用起来十分方便.那C# ...

  2. Java 实现简答的单链表的功能

    作者:林子木  博客网址:http://blog.csdn.net/wolinxuebin 參考网址:http://blog.csdn.net/sunsaigang/article/details/5 ...

  3. Spark集群搭建简配+它到底有多快?【单挑纯C/CPP/HADOOP】

    最近耳闻Spark风生水起,这两天利用休息时间研究了一下,果然还是给人不少惊喜.可惜,笔者不善JAVA,只有PYTHON和SCALA接口.花了不少时间从零开始认识PYTHON和SCALA,不少时间答了 ...

  4. 开发一款直播APP系统软件应该有哪些功能,如何开发?

    1.技术实现层面: 技术相对都比较成熟,设备也都支持硬编码.IOS还提供现成的 Video ToolBox框架,可以对摄像头和流媒体数据结构进行处理,但Video ToolBox框架只兼容8.0以上版 ...

  5. golang使用http client发起get和post请求示例

    [转自 http://www.01happy.com/golang-http-client-get-and-post/ ] get请求 get请求可以直接http.Get方法,非常简单. 1 2 3 ...

  6. HttpServer:一款Windows平台下基于IOCP模型的高并发轻量级web服务器

    HttpServer的特点1.完全采用IOCP模型,实现真正的异步IO,高并发.高可靠: 2.支持4G以上文件下载: 3.支持断点续传: 4.轻量级,体积小,服务器文件仅200多K,无任何依赖库: 5 ...

  7. 【电子取证:抓包篇】Fiddler 抓包配置与数据分析(简)

    Fiddler 抓包配置与分析(简) 简单介绍了Fiddler抓包常用到的基础知识,看完可以大概明白怎么分析抓包数据 ---[suy999]   Fiddler 抓包工具,可以将网络传输发送与接受的数 ...

  8. http状态码是什么,有什么用,在哪里查看,分别代表什么意思?

    写在前面: 当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求.当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码的信息头用以响应浏览器的请求.本文主要是:关于ht ...

  9. Http协议请求头、响应头、响应码

    Http部分请求头 Accept 客户机通过这个头,告诉服务器,它支持哪些数据类型 Accept-Charset 客户机通过这个头,告诉服务器,它支持的编码 Accept-Encoding 客户机通过 ...

  10. urllib笔记

    在Python 3中,urllib2被合并到了urllib中,叫做urllib.request 和 urllib.error .urllib整个模块分为urllib.request, urllib.p ...

随机推荐

  1. 时间轮在 Netty , Kafka 中的设计与实现

    本文基于 Netty 4.1.112.Final , Kafka 3.9.0 版本进行讨论 在业务开发的场景中,我们经常会遇到很多定时任务的需求.比如,生成业务报表,周期性对账,同步数据,订单支付超时 ...

  2. Qt/C++音视频开发53-本地摄像头推流/桌面推流/文件推流/监控推流等

    一.前言 编写这个推流程序,最开始设计的时候是用视频文件推流,后面陆续增加了监控摄像头推流(其实就是rtsp视频流).网络电台和视频推流(一般是rtmp或者http开头m3u8结尾的视频流).本地摄像 ...

  3. Qt音视频开发30-Onvif事件订阅

    一.前言 能够接收摄像机的报警事件,比如几乎所有的摄像机后面会增加报警输入输出接口,如果用户外接了报警输入,则当触发报警以后,对应的事件也会通过onvif传出去,这样就相当于兼容了所有onvif摄像机 ...

  4. Element库的Vue版本ElementUI的本地引入方法

    最近刚接触ElementUI,发现官方介绍的使用方法中只有npm安装和CDN引入这两种方式,没有本地引入的方法. 因为我的学习环境有时候是断网状态的,所以自己研究了一下本地引入的方法,记录在此. 1. ...

  5. 【OpenGL ES】GLSL基础语法

    1 前言 ​ 本文将介绍 GLSL 中数据类型.数组.结构体.宏.运算符.向量运算.矩阵运算.函数.流程控制.精度限定符.变量限定符(in.out.inout).函数参数限定符等内容,另外提供了一个 ...

  6. Shapefile代码示例

    Shapefile代码示例 1. 读取Shapefile文件 1.1 实现思路 graph TD A[查找必要文件] --> B[获取文件编码] B --> C[打开图层] C --> ...

  7. [.NET] 使用客户端缓存提高API性能

    使用客户端缓存提高API性能 摘要 在现代应用程序中,性能始终是一个关键的考虑因素.无论是提高响应速度,降低延迟,还是减轻服务器负载,开发者都在寻找各种方法来优化他们的API.在Web开发中,利用客户 ...

  8. w3cschool-Python3 爬虫抓取、深度/机器学习类

    https://www.w3cschool.cn/python3/python3-enbl2pw9.html (1) requests安装 在cmd中,使用如下指令安装requests: pip in ...

  9. manim边学边做--局部变换

    本次介绍的两个用于变换的动画类:TransformMatchingShapes和TransformMatchingTex. 它们的主要特点是对一组对象或一段文本进行局部变换,适用于复杂的图形或者文本的 ...

  10. Q:oracle库,同时更新表的两个字段?

    在执行这些操作之前,建议先备份数据或在一个测试环境中验证这些SQL语句的效果,以避免意外的数据丢失. 1.使用 UPDATE 结合子查询: 对于t2表中col字段为空的记录,如果t1表中有对应的col ...