Go1.18新特性使用Generics泛型进行流式处理
作者:摇摆的小虎牙 发布时间:2024-02-17 07:12:42
前言
Stream 是一个基于 Go 1.18+ 泛型的流式处理库, 它支持并行处理流中的数据. 并行流会将元素平均划分多个的分区, 并创建相同数量的 goroutine 执行, 并且会保证处理完成后流中元素保持原始顺序.
GitHub - xyctruth/stream: A Stream library based on Go 1.18+ Generics (Support Parallel Stream)
安装
需要安装 Go 1.18+ 版本
$ go get github.com/xyctruth/stream
在代码中导入它
import "github.com/xyctruth/stream"
基础
s := stream.NewSliceByOrdered([]string{"d", "a", "b", "c", "a"}).
Filter(func(s string) bool { return s != "b" }).
Map(func(s string) string { return "class_" + s }).
Sort().
Distinct().
ToSlice()
// 需要转换切片元素的类型
s := stream.NewSliceByMapping[int, string, string]([]int{1, 2, 3, 4, 5}).
Filter(func(v int) bool { return v >3 }).
Map(func(v int) string { return "mapping_" + strconv.Itoa(v) }).
Reduce(func(r string, v string) string { return r + v })
类型约束
any
接受任何类型的元素, 所以不能使用 ==
!=
>
<
比较元素, 导致你不能使用 Sort(), Find()...等函数 ,但是你可以使用 SortFunc(fn), FindFunc(fn)... 代替
type SliceStream[E any] struct {
slice []E
}
stream.NewSlice([]int{1, 2, 3, 7, 1})
comparable
接收的类型可以使用 ==
!=
比较元素, 但仍然不能使用 >
<
比较元素, 因此你不能使用 Sort(), Min()...等函数 ,但是你可以使用 SortFunc(fn), MinFunc()... 代替
type SliceComparableStream[E comparable] struct {
SliceStream[E]
}
stream.NewSliceByComparable([]int{1, 2, 3, 7, 1})
constraints.Ordered
接收的类型可以使用 ==
!=
>
<
, 所以可以使用所有的函数
type SliceOrderedStream[E constraints.Ordered] struct {
SliceComparableStream[E]
}
stream.NewSliceByOrdered([]int{1, 2, 3, 7, 1})
类型转换
有些时候我们需要使用 Map
,Reduce
转换切片元素的类型,但是很遗憾目前 Golang 并不支持结构体的方法有额外的类型参数,所有类型参数必须在结构体中声明。在 Golang 支持之前我们暂时使用临时方案解决这个问题。
// SliceMappingStream Need to convert the type of slice elements.
// - E elements type
// - MapE map elements type
// - ReduceE reduce elements type
type SliceMappingStream[E any, MapE any, ReduceE any] struct {
SliceStream[E]
}
s := stream.NewSliceByMapping[int, string, string]([]int{1, 2, 3, 4, 5}).
Filter(func(v int) bool { return v >3 }).
Map(func(v int) string { return "mapping_" + strconv.Itoa(v) }).
Reduce(func(r string, v string) string { return r + v })
并行
Parallel
函数接收一个 goroutines int
参数. 如果 goroutines>1 则开启并行, 否则关闭并行, 默认流是关闭并行的。
并行会将流中的元素平均划分多个的分区, 并创建相同数量的 goroutine 执行, 并且会保证处理完成后流中元素保持原始顺序.
s := stream.NewSliceByOrdered([]string{"d", "a", "b", "c", "a"}).
Parallel(10).
Filter(func(s string) bool {
// 一些耗时操作
return s != "b"
}).
Map(func(s string) string {
// 一些耗时操作
return "class_" + s
}).
ForEach(
func(index int, s string) {
// 一些耗时操作
},
).ToSlice()
并行类型
First
: 一旦获得第一个返回值,并行处理就结束. For: AllMatch, AnyMatch, FindFuncALL
: 所有元素都需要并行处理,得到所有返回值,然后并行结束. For: Map, FilterAction
: 所有元素需要并行处理,不需要返回值. For: ForEach, Action
并行 goroutines
开启并行 goroutine 数量在面对 CPU 操作与 IO 操作有着不同的选择。
一般面对 CPU 操作时 goroutine 数量不需要设置大于 CPU 核心数,而 IO 操作时 goroutine 数量可以设置远远大于 CPU 核心数.
CPU 操作
NewSlice(s).Parallel(goroutines).ForEach(func(i int, v int) {
sort.Ints(newArray(1000)) // 模拟 CPU 耗时操作
})
使用6个cpu核心进行基准测试
go test -run=^$ -benchtime=5s -cpu=6 -bench=^BenchmarkParallelByCPU
goarch: amd64
pkg: github.com/xyctruth/stream
cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
BenchmarkParallelByCPU/no_parallel(0)-6 717 9183119 ns/op
BenchmarkParallelByCPU/goroutines(2)-6 1396 4303113 ns/op
BenchmarkParallelByCPU/goroutines(4)-6 2539 2388197 ns/op
BenchmarkParallelByCPU/goroutines(6)-6 2932 2159407 ns/op
BenchmarkParallelByCPU/goroutines(8)-6 2334 2577405 ns/op
BenchmarkParallelByCPU/goroutines(10)-6 2649 2352926 ns/op
IO 操作
NewSlice(s).Parallel(goroutines).ForEach(func(i int, v int) {
time.Sleep(time.Millisecond) // 模拟 IO 耗时操作
})
使用6个cpu核心进行基准测试
go test -run=^$ -benchtime=5s -cpu=6 -bench=^BenchmarkParallelByIO
goos: darwin
goarch: amd64
pkg: github.com/xyctruth/stream
cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
BenchmarkParallelByIO/no_parallel(0)-6 52 102023558 ns/op
BenchmarkParallelByIO/goroutines(2)-6 100 55807303 ns/op
BenchmarkParallelByIO/goroutines(4)-6 214 27868725 ns/op
BenchmarkParallelByIO/goroutines(6)-6 315 18925789 ns/op
BenchmarkParallelByIO/goroutines(8)-6 411 14439700 ns/op
BenchmarkParallelByIO/goroutines(10)-6 537 11164758 ns/op
BenchmarkParallelByIO/goroutines(50)-6 2629 2310602 ns/op
BenchmarkParallelByIO/goroutines(100)-6 5094 1221887 ns/op
项目地址 https://github.com/xyctruth/stream
来源:https://juejin.cn/post/7075227613299474446


猜你喜欢
- 众所周知当前(甚至接下来的几年)最酷的东西是iPhone。不仅仅是因为iPhone看起来不错,它们在网站方面也很不错。而且,更重要的是,很多
- Cloudinary提供了一个API,用于将图像、视频和任何其他类型的文件上传到云端。上传到Cloudinary的文件通过安全备份和修订历史
- vue页面的打印和下载PDF(加水印)vue项目页面的打印打印的不用说,调用 window.print() 的方法即可;注意点:如果用到背景
- 一、可以使用以下步骤获取两个以逗号分割的字符串的并集:使用explode函数将两个字符串转换为数组,以便可以对其执行操作。使用array_m
- 首先说明,伪造访问来路不是什么光明正大的事情,目的就是为了欺骗服务器。原本以为给 XMLHTTP 对象增加一个 Referer 的heade
- 一 前期说明:我运行项目的环境是nginx+php,存储代码用的是gitlab,python版本:3.6 django版本:2.2.1 my
- 这里我们将分析一下如何开启和使用smarty缓存,如何清除smarty缓存以及smarty的全局缓存,部分缓存,局部缓存三种缓存机制。一、开
- python写文件时覆盖原来写的方法:使用“open('文件名','w')”语句,以写模式打开文件,然后使用
- 目录循环加判断retrying我们在程序开发中,经常会需要请求一些外部的接口资源,而且我们不能保证每次请求一定会成功,所以这些涉及到网络请求
- 微信小程序 滚动选择器(时间日期)详解微信小程序自己封装了很多控件,用起来确实很方便,如果这是Android里面,还需要自己去定
- 代码需要先导入pandasarr的数据类型为一维的np.arrayimport pandas as pdarr[~pd.isnull(arr
- 这篇文章主要介绍了python yield和Generator函数用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参
- Python自动的os库是和操作系统交互的库,常用的操作包括文件/目录操作,路径操作,环境变量操作和执行系统命令等。文件/目录操作获取当前目
- 1.字符串大小写转换string.title() #将字符串中所有单词的首字母以大写形式显示string.upper() #将字符串中所有字
- 前言:我们想要在爬虫中使用xpath、beautifulsoup、正则表达式,css选择器等来提取想要的数据,但是因为scrapy是一个比较
- 检查 MySQL 数据库的启动时间Linux 系统中的 systemd 和 mysqld_safe 会在 mysqld 进程 crash 后
- 最近网上再度兴起了CSS布局和Table 布局的争论。我最初颇有些不以为然:我原以为CSS 布局的意义早已深入人心,却没想到还有这么多设计师
- 一、默认参数python为了简化函数的调用,提供了默认参数机制:这样在调用pow函数时,就可以省略最后一个参数不写:在定义有默认参数的函数时
- 首先,简单介绍一下EXECL中工作簿和工作表的区别:工作簿的英文是BOOK(WORKBOOK),工作表的英文是SHEET(WORKSHEET
- 学习神经网络已经有一段时间,从普通的BP神经网络到LSTM长短期记忆网络都有一定的了解,但是从未系统的把整个神经网络的结构记录下来,我相信这