go-zero(十三)使用MapReduce并发
go zero 使用MapReduce并发
一、MapReduce 介绍
MapReduce 是一种用于并行计算的编程模型,特别适合在大规模数据处理场景中简化逻辑代码。
官方文档:
https://go-zero.dev/docs/components/mr
1. MapReduce 的核心概念
在 MapReduce 中,主要有以下三个核心步骤:
a. Generate (生成数据):
- 数据的初始输入阶段。可以是一个简单的循环,也可以是从数据库、文件或其他来源加载数据。
b. Mapper (映射): - 将输入数据映射为中间结果。通常用来过滤、转换、查询或处理数据。
c. Reducer (归约): - 对映射后的数据进行汇总处理,生成最终的结果。
在 go zero 中,mr.MapReduce 的具体代码如下:
func MapReduce[T, U, V any](generate GenerateFunc[T], mapper MapperFunc[T, U], reducer ReducerFunc[U, V],opts ...Option) (V, error) {panicChan := &onceChan{channel: make(chan any)}source := buildSource(generate, panicChan)return mapReduceWithPanicChan(source, panicChan, mapper, reducer, opts...)
}
2. 为什么需要 MapReduce
在实际的业务场景中我们常常需要从不同的 rpc 服务中获取相应属性来组装成复杂对象。
比如要查询商品详情:
- 商品服务-查询商品属性
- 库存服务-查询库存属性
- 价格服务-查询价格属性
- 营销服务-查询营销属性
如果是串行调用的话响应时间会随着 rpc 调用次数呈线性增长,所以我们要优化性能一般会将串行改并行。
简单的场景下使用 WaitGroup 也能够满足需求,但是如果我们需要对 rpc 调用返回的数据进行校验、数据加工转换、数据汇总呢?继续使用 WaitGroup 就有点力不从心了.。
二、项目构建
接下来我们使用一个文章列表功能简单的演示下
1. article数据表
这是存储文章信息的表,包含标题、内容、作者、评论数等字段。
CREATE TABLE `article` (`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',`title` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '标题' COLLATE 'utf8mb4_bin',`content` TEXT NOT NULL COMMENT '内容' COLLATE 'utf8_unicode_ci',`cover` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '封面' COLLATE 'utf8mb4_bin',`description` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '描述' COLLATE 'utf8mb4_bin',PRIMARY KEY (`id`)
);
2.article.api
在实际开发中,应该传入作者ID、游标、页码、排序方法等信息,这里为了方便演示就不传入参数了,API 定义如下:
syntax = "v1"type (ArticleInfo {ArticleId int64 `json:"article_id"`Title string `json:"title"`Content string `json:"content"`Description string `json:"description"`Cover string `json:"cover"`}ArticleListResponse {Articles []ArticleInfo `json:"articles"`}
)@server (prefix: /v1/article
)
service article-api {@handler Articlelisthandlerpost /list returns (ArticleListResponse)
}
三、使用 MapReduce
拉取库
go get github.com/zeromicro/go-zero/core/mr
1.实现文章列表
我们使用 MapReduce 来并行处理文章数据,
func (l *ArticlelistLogic) Articlelist() (resp *types.ArticleListResponse, err error) {// Step 1: Generate 数据//这里为了方便我使用了简单for循环产生文档IDgenerateFunc := func(source chan<- int) {for id := 1; id < 50; id++ { // 模拟文章 ID 数据source <- id}}articleModel := l.svcCtx.ArticleModel// Step 2: Mapper 映射处理mapperFunc := func(id int, writer mr.Writer[*types.ArticleInfo], cancel func(error)) {//使用产生id,查询文章详情one, err := articleModel.FindOne(l.ctx, uint64(id)) // 查找单篇文章if err != nil {return // 跳过错误}//FindOne返回的是 *model.Article类型,Mapper映射的类型为*types.ArticleInfo//所以需要转换一下articleInfo := &types.ArticleInfo{ArticleId: int64(one.Id),Title: one.Title,Content: one.Content,Description: one.Description,Cover: one.Cover,}writer.Write(articleInfo) // 写入中间结果}// Step 3: Reducer 汇总处理reduceFunc := func(pipe <-chan *types.ArticleInfo, writer mr.Writer[[]types.ArticleInfo], cancel func(error)) {var articleList []types.ArticleInfofor article := range pipe {articleList = append(articleList, *article) }writer.Write(articleList) // 写入最终结果}// 调用 MapReduce//mr.WithWorkers(5) 允许调用者自定义并发工作线程数。//如果不传入mr.WithWorkers ,默认Workers为16个reduce, err := mr.MapReduce(generateFunc, mapperFunc, reduceFunc, mr.WithWorkers(5)) if err != nil {return nil, err // 处理错误}// 返回结果return &types.ArticleListResponse{Articles: reduce,}, nil
}

2. 详细讲解
Step 1: Generate 数据
generateFunc 的作用是提供初始数据。在本例中,我们通过一个循环生成了文章的 ID:
generateFunc := func(source chan<- int) {for id := 1; id < 50; id++ {source <- id}
}
Step 2: Mapper 映射处理
mapperFunc 用于处理每一个文章 ID,并将其转换为 ArticleInfo。
- 使用
articleModel.FindOne从数据库中获取文章数据。 - 如果获取失败,跳过该 ID。
- 将结果通过
writer.Write写入到下一步。
mapperFunc := func(id int, writer mr.Writer[*types.ArticleInfo], cancel func(error)) {one, err := articleModel.FindOne(l.ctx, uint64(id))if err != nil {return}articleInfo := &types.ArticleInfo{ArticleId: int64(one.Id),Title: one.Title,Content: one.Content,Description: one.Description,Cover: one.Cover,}writer.Write(articleInfo)
}
Step 3: Reducer 汇总处理
reduceFunc 将 mapperFunc 的结果汇总为最终的 []types.ArticleInfo。
- 遍历管道中的每个
*types.ArticleInfo。 - 将解引用后的
ArticleInfo添加到结果列表。
reduceFunc := func(pipe <-chan *types.ArticleInfo, writer mr.Writer[[]types.ArticleInfo], cancel func(error)) {var articleList []types.ArticleInfofor article := range pipe {articleList = append(articleList, *article)}writer.Write(articleList)
}
3. 测试运行
向 /v1/article/list 发送 POST 请求:
curl -X POST http://localhost:8888/v1/article/list
运行结果如下:
{"articles": [{"article_id": 1,"title": "标题1","content": "这是内容1","description": "描述1","cover": "封面1.jpg"},...]
}
4.效率对比
普通循环
为了更直观的对比效率,我们使用普通循环再次实现下文章列表:
func (l *ArticlelistLogic) Articlelist() (resp *types.ArticleListResponse, err error) {// todo: add your logic here and delete this linetime1 := time.Now()var articleList []types.ArticleInfoarticleModel := l.svcCtx.ArticleModelfor id := 1; id < 50; id++ {article, _ := articleModel.FindOne(l.ctx, uint64(id))articleInfo := types.ArticleInfo{ArticleId: int64(article.Id),Title: article.Title,Content: article.Content,Description: article.Description,Cover: article.Cover,}articleList = append(articleList, articleInfo)}time2 := time.Now()logx.Info("执行时间为:", time2.Sub(time1))return &types.ArticleListResponse{Articles: articleList,}, nil}
效率对比
这个执行时间可能每次都不一样,但是进过多次对比, 使用mapreduce 效率是高于普通方法的
使用串行调用时间:

使用MapReduce消耗时间:

相关文章:
go-zero(十三)使用MapReduce并发
go zero 使用MapReduce并发 一、MapReduce 介绍 MapReduce 是一种用于并行计算的编程模型,特别适合在大规模数据处理场景中简化逻辑代码。 官方文档: https://go-zero.dev/docs/components/mr 1. MapReduce 的核心概念 在 MapReduce 中,主…...
【实操之 图像处理与百度api-python版本】
1 cgg带你建个工程 如图 不然你的pip baidu-aip 用不了 先对图片进行一点处理 $ 灰度处理 $ 滤波处理 参考 import cv2 import os def preprocess_images(input_folder, output_folder):# 确保输出文件夹存在if not os.path.exists(output_folder):os.makedirs(output_fol…...
java 导出word锁定且部分内容解锁可编辑
使用 Apache POI 创建带编辑限制的 Word 文档 在日常工作中,我们可能需要生成一些带有编辑限制的 Word 文档,例如某些段落只能被查看,而其他段落可以自由编辑。本文介绍如何使用 Apache POI 创建这样的文档,并通过代码实现相应的…...
SQL 在线格式化 - 加菲工具
SQL 在线格式化 打开网站 加菲工具 选择“SQL 在线格式化” 或者直接访问 https://www.orcc.online/tools/sql 输入sql,点击上方的格式化按钮即可 输入框得到格式化后的sql结果...
大数据法律法规——《关键信息基础设施安全保护条例》(山东省大数据职称考试)
大数据分析应用-初级 第一部分 基础知识 一、大数据法律法规、政策文件、相关标准 二、计算机基础知识 三、信息化基础知识 四、密码学 五、大数据安全 六、数据库系统 七、数据仓库. 第二部分 专业知识 一、大数据技术与应用 二、大数据分析模型 三、数据科学 大数据法律法规…...
【CVE-2024-5660】ARM CPU漏洞:硬件页面聚合(HPA)安全通告
安全之安全(security)博客目录导读 目录 一、概述 二、修改历史 三、什么是硬件页面聚合? 四、修复解决 一、概述 在一些基于arm的cpu中发现了一个问题,该问题可能允许修改的、不受信任的客户机操作系统...
数智读书笔记系列008 智人之上:从石器时代到AI时代的信息网络简史
书名:智人之上:从石器时代到AI时代的信息网络简史 作者:[以]尤瓦尔赫拉利 译者:林俊宏 出版时间:2024-09-01 ISBN:9787521768527 中信出版集团制作发行 作者信息 尤瓦尔・赫拉利 1976 年出生于以色列海法,是牛津大学历史学…...
将 Ubuntu 22.04 LTS 升级到 24.04 LTS
Ubuntu 24.04 LTS 将支持 Ubuntu 桌面、Ubuntu 服务器和 Ubuntu Core 5 年,直到 2029 年 4 月。 本文将介绍如何将当前 Ubuntu 22.04 系统升级到最新 Ubuntu 24.04 LTS版本。 备份个人数据 以防万一,把系统中的重要数据自己备份一下~ 安装配置SSH访问…...
【自动驾驶】Ubuntu20.04安装ROS1 Noetic
【自动驾驶】Ubuntu20.04安装ROS1 Noetic 方式一:官方教程方式二:鱼香ROS脚本安装ROS配置rosdep配置ROS环境 测试ROS1 Noetic是否安装成功 方式一:官方教程 https://wiki.ros.org/noetic/Installation/Ubuntu 方式二:鱼香ROS脚本 …...
(转,自阅,侵删)【LaTeX学习笔记】一文入门LaTeX(超详细)
【LaTeX学习笔记】一文入门LaTeX(超详细)-阿里云开发者社区LaTeX中主要分为导言区和正文区导言区通常用于定义文档的格式、语言等(全局设置)。常用的LaTex命令主要有\documentclass,\usepackage等。下面分别对几个常用…...
css的选择器有哪些?权重由大到小是怎么排序的?
CSS选择器有很多种,下面是常见的选择器类型,并按照其权重(即优先级)从高到低进行排序。 CSS选择器类型 通用选择器 (*) (通配符选择器) 选择所有元素,权重最低。 例如:* { color:…...
CTF知识集-PHP特性
title: CTF知识集-PHP特性 写在开头可能会用到的提示 call_user_func 调用的函数可以不区分大小写preg_match过滤存在长度溢出,长度超过100w检测失效。str_repeat(‘show’,250000); 生成100w个字符preg_match是无法处理数组的,例如:preg_match( n u m…...
比特币是否会取代美元(以及其他主权货币)
上图是 Olivier Blanchard 宏观经济学第八版的英文版内容。这里用中文解释。 1. 背景与现状: 比特币的规模与美元相比仍然很小: 截至 2018 年 12 月,比特币的总流通量为 1730 万枚,每枚价值 $3,900,总市值约 $670 亿…...
WPF+MVVM案例实战与特效(三十七)- 实现带有水印和圆角的自定义 TextBox 控件
文章目录 1、概述2、案例实现1、基本功能2、代码实现3、控件应用4、案例效果4、总结1、概述 在开发用户界面时,TextBox 是最常见的输入控件之一。为了提升用户体验,我们经常需要为 TextBox 添加一些额外的功能,例如显示提示文本(水印)和设置圆角边框。本文将详细介绍如何…...
深度学习训练参数之学习率介绍
学习率 1. 什么是学习率 学习率是训练神经网络的重要超参数之一,它代表在每一次迭代中梯度向损失函数最优解移动的步长,通常用 η \eta η 表示。它的大小决定网络学习速度的快慢。在网络训练过程中,模型通过样本数据给出预测值࿰…...
导游现场面试需要注意的问题
今天给大家带来一些导游现场面试需要注意的问题,大部分的城市导游考试已经考完了,但是还有一些城市的十二月份才考,有需要的朋友们赶紧来看,有备无患。 01、做好充足准备 认真准备做好每个景点的讲解介绍,不要抱有侥幸…...
Burp suite 3 (泷羽sec)
声明 学习视频来自B站UP主 泷羽sec,如涉及侵泷羽sec权马上删除文章。 笔记只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 这节课旨在扩大自己在网络安全方面的知识面,了解网络安全领域的见闻,了…...
LabVIEW前面板无法显示的常见原因
当 LabVIEW 前面板显示为白色或黑色时,可能由于控件可视性设置、显卡驱动问题、程序错误或 LabVIEW 设置不当引起。通过检查面板设置、更新驱动、重启程序等方式可有效解决此问题。 遇到前面板无法显示或显示为白色/黑色的情况,可能有以下几种原因。可以…...
【Syncfusion系列】Diagram 杂谈 第三篇 序列化和反序列化
目录 序列化保存C# 代码示例, 方式1 :C# 代码示例, 方式2 : 反序列化加载C# 代码示例, 方式1:C# 代码示例, 方式2: **如何序列化自定义属性**序列化和反序列化都存在的一个问题解决方式 图表是否已修改&…...
Apache APISIX快速入门
本文将介绍Apache APISIX,这是一个开源API网关,可以处理速率限制选项,并且可以轻松地完全控制外部流量对内部后端API服务的访问。我们将看看是什么使它从其他网关服务中脱颖而出。我们还将详细讨论如何开始使用Apache APISIX网关。 在深入讨…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
