Go http请求排队处理实战示例
怎么入门Golang编程?需要学习哪些知识点?这是新手们刚接触编程时常见的问题;下面golang学习网就来给大家整理分享一些知识点,希望能够给初学者一些帮助。本篇文章就来介绍《Go http请求排队处理实战示例》,涉及到请求、HTTP、排队处理,有需要的可以收藏一下
一、http请求的顺序处理方式
在高并发场景下,为了降低系统压力,都会使用一种让请求排队处理的机制。本文就介绍在Go中是如何实现的。
首先,我们看下正常的请求处理逻辑。 客户端发送请求,web server接收请求,然后就是处理请求,最后响应给客户端这样一个顺序的逻辑。如下图所示:

代码实现如下:
package main
import (
"fmt"
"net/http"
)
func main() {
myHandler := MyHandler{}
http.Handle("/", &myHandler)
http.ListenAndServe(":8080", nil)
}
type MyHandler struct {
}
func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello Go"))
}
在浏览器中输入 http://localhost:8080/,就能在页面上显示出“Hello Go”的页面来。
通常情况下,大家在开发web系统的时候,一般都是这么处理请求。接下来我们看在高并发下如何实现让请求进行排队处理。
二、http请求的异步处理方式--排队处理
让http请求进入到队列,我们也称为异步处理方式。其基本思想就是将接收到的请求的上下文(即request和response)以及处理逻辑包装成一个工作单元,然后将其放到队列,然后该工作单元等待消费的工作线程处理该job,处理完成后再返回给客户端。 流程如下图:

该实现中会有三个关键的元素:工作执行单元、队列、消费者。下面我们逐一看下各自的职责及实现。
工作单元
该工作单元主要是封装请求的上下文信息(request和response)、请求的处理逻辑以及该工作单元是否被执行完成的状态。
请求的处理逻辑实际上就是原来在顺序处理流程中的具体函数,如果是mvc模式的话就是controller里的一个具体的action。
在Go中实现通信的方式一般是使用通道。所以,在工作单元中有一个通道,当该工作单元执行完具体的处理逻辑后,就往该通道中写入一个消息,以通知主协程该次请求已完成,可以返回给客户端了。
所以,一个http请求的处理逻辑看起来就像是下面这样:
func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
将w和r包装成工作单元job
将job入队
等待job执行完成
本次请求处理完毕
}
下面我们看下工作单元的具体实现,这里我们将其定义为一个Job结构体:
type Job struct {
DoneChan chan struct{}
handleJob func(j FlowJob) error //具体的处理逻辑
}
Job结构体中有一个handleJob,其类型是一个函数,即处理请求的逻辑部分。DoneChan通道用来让该单元进行阻塞等待,并当handleJob执行完毕后发送消息通知的。
下面我们再看看该Job的相关行为:
// 消费者从队列中取出该job时 执行具体的处理逻辑
func (job *Job) Execute() error {
fmt.Println("job start to execute ")
return job.handleJob(job)
}
// 执行完Execute后,调用该函数以通知主线程中等待的job
func (job *Job) Done() {
job.DoneChan
<h3>队列</h3>
<p>队列主要是用来存储工作单元的。是处理请求的主协程和消费协程之间的纽带。队列具有列表、容量、当前元素个数等关键元素组成。如下:</p>
<pre class="brush:go;">type JobQueue struct {
mu sync.Mutex
noticeChan chan struct{}
queue *list.List
size int
capacity int
}
其行为主要有入队、出队、移除等操作。定义如下:
// 初始化队列
func NewJobQueue(cap int) *JobQueue {
return &JobQueue{
capacity: cap,
queue: list.New(),
noticeChan: make(chan struct{}, 1),
}
}
// 工作单元入队
func (q *JobQueue) PushJob(job *Job) {
q.mu.Lock()
defer q.mu.Unlock()
q.size++
if q.size > q.capacity {
q.RemoveLeastJob()
}
q.queue.PushBack(job)
q.noticeChan
<p>这里我们主要解释一下入队的操作流程:</p>
- 1 首先是队列的元素个数size++
- 2 判断size是否超过最大容量capacity
- 3 若超过最大容量,则将队列中最后一个元素移除。因为该元素等待时间最长,认为是超时的情况。
- 4 将新接收的工作单元放入到队尾。
- 5 往noticeChan通道中写入一个消息,以便通知消费协程处理Job。
由以上可知,noticeChan是队列和消费者协程之间的纽带。下面我们来看看消费者的实现。
消费者协程
消费者协程的职责是监听队列,并从队列中获取工作单元,执行工作单元的具体处理逻辑。在实际应用中,可以根据系统的承载能力启用多个消费协程。在本文中,为了方便讲解,我们只启用一个消费协程。
我们定义一个WorkerManager结构体,负责管理具体的消费协程。该WorkerManager有一个属性是工作队列,所有启动的消费协程都需要从该工作队列中获取工作单元。代码实现如下:
type WorkerManager struct {
jobQueue *JobQueue
}
func NewWorkerManager(jobQueue *JobQueue) *WorkerManager {
return &WorkerManager{
jobQueue: jobQueue,
}
}
func (m *WorkerManager) createWorker() error {
go func() {
fmt.Println("start the worker success")
var job FlowJob
for {
select {
case
<p>在代码中我们可以看到,createWorker中的逻辑实际是一个for循环,然后通过select监听队列的noticeChan通道,当获取到工作单元时,就执行工作单元中的handleJob方法。执行完后,通过job.Done()方法通知在主协程中还等待的job。这样整个流程就形成了闭环。</p>
<h3>完整代码</h3>
<p>我们现在看下整体的处理流程,如下图:</p>
<p style="text-align:center"><img alt="" src="/uploads/20221223/167175360263a4ef825c6c2.jpg"></p>
<p>现在我们写一个测试demo。在这里我们定义了一个全局的flowControl结构体,以作为队列和工作协程的管理。代码如下:</p>
<pre class="brush:go;">package main
import (
"container/list"
"fmt"
"net/http"
"sync"
)
func main() {
flowControl := NewFlowControl()
myHandler := MyHandler{
flowControl: flowControl,
}
http.Handle("/", &myHandler)
http.ListenAndServe(":8080", nil)
}
type MyHandler struct {
flowControl *FlowControl
}
func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Println("recieve http request")
job := &Job{
DoneChan: make(chan struct{}, 1),
handleJob: func(job *Job) error {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte("Hello World"))
return nil
},
}
h.flowControl.CommitJob(job)
fmt.Println("commit job to job queue success")
job.WaitDone()
}
type FlowControl struct {
jobQueue *JobQueue
wm *WorkerManager
}
func NewFlowControl() *FlowControl {
jobQueue := NewJobQueue(10)
fmt.Println("init job queue success")
m := NewWorkerManager(jobQueue)
m.createWorker()
fmt.Println("init worker success")
control := &FlowControl{
jobQueue: jobQueue,
wm: m,
}
fmt.Println("init flowcontrol success")
return control
}
func (c *FlowControl) CommitJob(job *Job) {
c.jobQueue.PushJob(job)
fmt.Println("commit job success")
}
之前有一篇文章是优先级队列,实际上就是该队列的高级实现版本,可以将不同的请求按优先级分配到不同的队列中。有兴趣的同学可参考:Go实战 单队列到优先级队列的实现
总结
通过将请求的上下文信息封装到一个工作单元中,并将其放入到队列中,然后通过消息通道的方式阻塞等待消费者执行完毕。同时在队列中通过设置队列的容量以解决请求过多而给系统造成压力的问题。
今天关于《Go http请求排队处理实战示例》的内容就介绍到这里了,是不是学起来一目了然!想要了解更多关于golang的内容请关注golang学习网公众号!
Go 实战单队列到优先级队列实现图文示例
- 上一篇
- Go 实战单队列到优先级队列实现图文示例
- 下一篇
- Go开发Gin项目添加jwt功能实例详解
-
- Golang · Go教程 | 6小时前 | 格式化输出 printf fmt库 格式化动词 Stringer接口
- Golangfmt库用法与格式化技巧解析
- 140浏览 收藏
-
- Golang · Go教程 | 6小时前 |
- Golang配置Protobuf安装教程
- 147浏览 收藏
-
- Golang · Go教程 | 6小时前 |
- Golang中介者模式实现与通信解耦技巧
- 378浏览 收藏
-
- Golang · Go教程 | 6小时前 |
- Golang多协程通信技巧分享
- 255浏览 收藏
-
- Golang · Go教程 | 7小时前 |
- Golang如何判断变量类型?
- 393浏览 收藏
-
- Golang · Go教程 | 7小时前 |
- Golang云原生微服务实战教程
- 310浏览 收藏
-
- Golang · Go教程 | 8小时前 |
- Golang迭代器与懒加载结合应用
- 110浏览 收藏
-
- Golang · Go教程 | 8小时前 | 性能优化 并发安全 Golangslicemap 预设容量 指针拷贝
- Golangslicemap优化技巧分享
- 412浏览 收藏
-
- Golang · Go教程 | 8小时前 |
- Golang代理模式与访问控制实现解析
- 423浏览 收藏
-
- Golang · Go教程 | 8小时前 |
- Golang事件管理模块实现教程
- 274浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3166次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3379次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3408次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4512次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3788次使用
-
- HTTP 的 response 中的响应体和头部是分开发送的吗?
- 2023-01-28 387浏览
-
- 使用Go http重试请求的示例
- 2022-12-28 329浏览
-
- B站等视频网站的弹幕用的是 websocket 还是轮询?
- 2023-02-16 447浏览
-
- Golang实现HTTP编程请求和响应
- 2022-12-28 101浏览
-
- golangNewRequest/gorequest实现http请求的示例代码
- 2023-01-24 343浏览

