在Go中过滤范型集合:性能回顾
在一个真实的 Golang 场景中使用泛型,同时寻找与 Stream filter(Predicate<? super T> predicate)和 Python list comprehension 等同的函数。我没有依赖现有的包,而是选择自己写一个过滤函数,以达到学习的目的
func filterStrings(collection []string, test func(string) bool) (f []string) {for _, s := range collection {if test(s) {f = append(f, s)}}return
}
然而,这只适用于字符串。如果我需要过滤一个整数的集合,那么我就需要另一个极其相似的函数。这对于一个范型函数来说似乎是一个完美的选择。
func filter[T any](collection []T, test func(T) bool) (f []T) {for _, e := range collection {if test(e) {f = append(f, e)}}return
}
让我们来分析类型化和范型版本之间的(少数)差异:
函数名后面是一个范型T的定义。
T被定义为任何类型。
输入 slice 中元素的类型从字符串变成了T
输入、输出的 clice 类型也从字符串变成了T
不多说了,让我们来写一些单元测试。首先,我需要一个随机集合(在我的例子中,是字符串)的生成器。
func generateStringCollection(size, strLen int) []string {var collection []stringfor i := 0; i < size; i++ {collection = append(collection, strings.Repeat(fmt.Sprintf("%c", rune('A'+(i%10))), strLen))}return collection
}
现在我可以写一个测试用例,判断 filterStrings 函数的输出与我的过滤范型器的输出相同。
func TestFilter(t *testing.T) {c := generateStringCollection(1000, 3)t.Run("the output of the typed and generic functions is the same", func(t *testing.T) {predicate := func(s string) bool { return s == "AAA" }filteredStrings := filterStrings(c, predicate)filteredElements := filter(c, predicate)if !reflect.DeepEqual(filteredStrings, filteredElements) {t.Errorf("the output of the two functions is not the same")}})
}
=== RUN TestFilter
=== RUN TestFilter/the_output_of_the_typed_and_generic_functions_is_the_same
--- PASS: TestFilter (0.00s)--- PASS: TestFilter/the_output_of_the_typed_and_generic_functions_is_the_same (0.00s)
PASS
考虑新函数在处理大的 slice 时的性能问题。我怎样才能确保它在这种情况下也能表现良好?
答案是:基准测试。用Go编写基准测试与单元测试很相似。
const (CollectionSize = 1000ElementSize = 3
)func BenchmarkFilter_Typed_Copying(b *testing.B) {c := generateStringCollection(CollectionSize, ElementSize)b.Run("Equals to AAA", func(b *testing.B) {for i := 0; i < b.N; i++ {filterStrings(c, func(s string) bool { return s == "AAA" })}})
}func BenchmarkFilter_Generics_Copying(b *testing.B) {c := generateStringCollection(CollectionSize, ElementSize)b.Run("Equals to AAA", func(b *testing.B) {for i := 0; i < b.N; i++ {filter(c, func(s string) bool { return s == "AAA" })}})
}
go test -bench=. -count=10 -benchmem
goos: darwin
goarch: arm64
pkg: github.com/timliudream/go-test/generic_test
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8 718408 1641 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8 718148 1640 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8 732939 1655 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8 723036 1639 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8 699075 1639 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8 707232 1643 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8 616422 1652 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8 730702 1649 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8 691488 1700 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8 717043 1646 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8 428851 2754 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8 428437 2762 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8 430444 2800 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8 429314 2757 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8 430938 2754 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8 429795 2754 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8 426714 2755 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8 418152 2755 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8 431739 2761 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8 412221 2755 ns/op 4080 B/op 8 allocs/op
PASS
ok github.com/timliudream/go-test/generic_test 25.005s
我对这个结果并不满意。看起来我用可读性换取了性能。
此外,我对分配的数量也有点担心。你注意到我的测试名称中的_Copying后缀了吗?那是因为我的两个过滤函数都是将过滤后的项目从输入集合复制到输出集合中。为什么我必须为这样一个简单的任务占用内存?
到最后,我需要做的是过滤原始的收集。我决定先解决这个问题。
func filterInPlace[T any](collection []T, test func(T) bool) []T {var position, size = 0, len(collection)for i := 0; i < size; i++ {if test(collection[i]) {collection[position] = collection[i]position++}}return collection[:position]
}
我不是把过滤后的结果写到一个新的集合中,然后再返回,而是把结果写回原来的集合中,并保留一个额外的索引,以便在过滤后的项目数上 "切 "出一个片断。
我的单元测试仍然通过,在改变了下面这行之后。
filteredStrings := filterStrings(c, predicate)
//filteredElements := filter(c, predicate)filteredElements := filterInPlace(c, predicate) // new memory-savvy function
再添加一个 bench 方法:
func BenchmarkFilter_Generics_InPlace(b *testing.B) {c := generateStringCollection(CollectionSize, 3)b.Run("Equals to AAA", func(b *testing.B) {for i := 0; i < b.N; i++ {filterInPlace(c, func(s string) bool { return s == "AAA" })}})
}
结果是出色的。
go test -bench=. -benchmem
goos: darwin
goarch: arm64
pkg: github.com/timliudream/go-test/generic_test
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8 713928 1642 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8 426055 2787 ns/op 4080 B/op 8 allocs/op
BenchmarkFilter_Generics_Inplace/Equals_to_AAA-8 483994 2467 ns/op 0 B/op 0 allocs/op
PASS
ok github.com/timliudream/go-test/generic_test 4.925s
不仅内存分配归零,而且性能也明显提高。
相关文章:
在Go中过滤范型集合:性能回顾
在一个真实的 Golang 场景中使用泛型,同时寻找与 Stream filter(Predicate<? super T> predicate)和 Python list comprehension 等同的函数。我没有依赖现有的包,而是选择自己写一个过滤函数,以达到学习的目的 func filterStrings(c…...
MATLAB 最小二乘直线拟合方法二 (36)
MATLAB 最小二乘直线拟合方法二 (36) 一、算法介绍二、算法实现1.代码2.结果一、算法介绍 这里介绍另一种拟合直线点云的方法,更为简单方便,结果与前者一致,主要内容直接复制代码使用即可,原理简单看代码即可,下面是具体的实现和拟合结果展示 二、算法实现 1.代码 代…...
Python 实现:OCR在图片中提取文字(基于Gradio实现)
Paddle OCR PaddleOCR 基于深度学习技术实现的,使用十分简单。 先看效果 可以看出来识别效果还是不错的,里面的“湿”字识别成了繁体字。如果不是连体字,就不会出现这个问题。 1.测试环境 操作系统:Win10 Python:3…...
idea插件开发报错: ZipException opening “slf4j.jar“: zip END header not found
错误信息 E:\idea-workspace\#idea-plugin\JSON2Object\src\main\java\com\hgy\plugin\json2object\GenerateAction.java:1: 错误: 无法访问com.hgy.plugin.json2object package com.hgy.plugin.json2object; ^ZipException opening "slf4j.jar": zip END header no…...
【Linux】多线程编程
目录 1. 线程基础知识 2. 线程创建 3. 线程ID(TID) 4. 线程终止 5. 线程取消 6. 线程等待 7. 线程分离 8. 线程互斥 8.1 初始化互斥量 8.2 销毁互斥量 8.3 互斥量加锁和解锁 9. 可重入和线程安全 10. 线程同步之条件变量 10.1 初始化条件变…...
【Mysql】InnoDB的表空间(九)
概述 表空间是一个在 InnoDB 中比较抽象的概念,对于系统表空间来说,对应着文件系统中一个或多个实际文件;而对于每个独立表空间来说,对应着文件系统中一个名为表名.ibd 的实际文件。可以把表空间想象成由很多个页组成的池子&…...
【09】ES6:Set 和 Map 数据结构
一、Set 1、基本语法 定义 Set 是一系列无序、没有重复值的数据集合。数组是一系列有序(下标索引)的数据集合。 Set 本身是一个构造函数,用来生成 Set 数据结构。 const s new Set() [2, 3, 5, 4, 5, 2, 2].forEach(x > s.add(x))fo…...
Java通过documents4j和libreoffice把word转为pdf
文章目录 word转pdf的相关第三方jar说明Linux系统安装LibreOffice在线安装离线安装word转pdf验证 Java工具类代码 word转pdf的相关第三方jar说明 docx4j 免费开源、稍微复杂点的word,样式完全乱了,且xalan升级为2.7.3后会报错。poi 免费开源、官方文档少…...
物联网时代的访问控制研究综述
A survey on Access Control in the Age of Internet of Things 文章目录 A B S T R A C T引言A. Comparison Between This Paper and Existing SurveysB. Contributions II.ACCESS CONTROL BACKGROUNDIII. ACCESS CONTROL CHALLENGES IN IOT SEARCHA. Characteristics of IoT …...
【产品经理】需求池和版本树
在这个人人都是产品经理的时代,每位入行的产品人进阶速度与到达高度各有不同。本文作者结合自身三年产品行业的经历,根据案例拆解产品行业的极简研发过程、需求池、版本树、产品自我优化等相关具体方法论。 一、产品研发的极简过程 1. 产品概述 产品就…...
Qt图像处理-OpenCv中Mat与QImage互转
Qt图像处理时需要OpenCv中Mat与QImage互转,具体代码如下 创建EditPhoto,头文件,使用前需要配置好opencv #include <QObject> #include <QImage> #include <QDebug>#include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> …...
构建外卖小程序:技术代码实践
在这个数字化的时代,外卖小程序已经成为餐饮业的一项重要工具。在本文中,我们将通过一些简单而实用的技术代码,向您展示如何构建一个基本的外卖小程序。我们将使用微信小程序平台作为例子,但这些原理同样适用于其他小程序平台。 …...
IDEA中显示方法、类注释信息
目录 一、IDEA测试版本及环境二、操作步骤2.1 鼠标悬停在某一个方法上,从而显示方法的注释信息2.2 调用方法时同步显示方法注释信息2.3 在new一个对象时,这个对象有很多重载的构造方法,想要重载的构造函数都显示出来 一、IDEA测试版本及环境 …...
《数据结构、算法与应用C++语言描述》- 堆排序 - 借助priority_queue的C++实现
堆排序 完整可编译运行代码见:Github::Data-Structures-Algorithms-and-Applications/_27HeapSort 定义 借助堆进行排序。先用n个待排序的元素初始化一个小根堆,然后从堆中逐个提取(即删除元素)元素。初始化的时间复杂度为O(n),大根堆中每…...
10.CSS浮动
CSS浮动 1.介绍 在最初,浮动是用来实现文字环绕图片效果的,现在浮动是主流的页面布局方式之一 2.作用 让元素脱离标准流,同一级的浮动的元素可以并排在一排显示 3.元素浮动后的特点 脱离文档流不管浮动前是什么元素,浮动后&…...
Angular 2 学习笔记
Angular 2 应用主要由以下 几个部分组成: 1、模块 (Modules): 2、组件 (Components): 3、模板 (Templates): 4、元数据 (Metadata): 5、数据绑定 (Data Binding) 6、指令 (Directives) 7、服务 (Servic…...
xcode 修改 target 中设备朝向崩溃
修改xcode的target中的设备朝向导致崩溃。 从日志上看好像没有什么特别的信息。 之后想了想,感觉这个应该还是跟xcode的配置有关系,不过改动的地方好像也只有plist。 就又翻腾了半天plist中的各种配置项,再把所有的用户权限提示相关的东西之…...
ZLMediaKit 编译以及测试(Centos 7.9 环境)
文章目录 一、前言二、编译器1、获取代码2、编译器2.1 编译器版本要求2.2 安装编译器 3、安装cmake4、依赖库4.1 依赖库列表4.2 安装依赖库4.2.1 安装libssl-dev和libsdl-dev4.2.2 安装 ffmpeg-devel依赖和ffmpeg依赖 三、构建和编译项目(启用WebRTC功能)…...
汽车清除积碳和清洗节气门
汽车清除积碳和清洗节气门 汽车需要清除积碳的部位检查积碳方法: 清除积碳和清洗节气门风险:燃油宝 第一次清除积碳1万公里2万公里3万公里--5万公里6万公里以上 汽车需要清除积碳的部位 节气门喷油嘴进气道燃烧室 检查积碳方法: 建议每3到5…...
RocketMQ 总体概括
目录 概述RocketMQ 领域模型MQ 解决的问题电商平台案例初步设计引入中间件设计 MQ 选型结束 概述 官网地址 RocketMQ 领域模型 官方领域模型概述 下面图,是在自己理解的基础上,对官方的模型图添加了一些。 Topic:主题,可以理解…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
