Golang Go语言中深度拷贝pcopy,性能升级版本来了
地址
https://github.com/antlabs/pcopy
作用
pcopy.Copy
主要用于两个类型间的深度拷贝, 前身是 deepcopy
新加预热函数。Copy 时打开加速开关,达到性能提升 4-10 倍的效果。
警告:
高性能的同时可能会有些 bug, 如果发现 bug 可以去掉pcopy.WithUsePreheat()
试下, 结果不一致,可以提 issue 。
feature
- 高性能, 相对第一个版本提升 4-10 倍的性能
- 支持异构结构体拷贝, dst 和 src 可以是不同的类型,会拷贝 dst 和 src 交集的部分
- 多类型支持 struct/map/slice/array/int...int64/uint...uint64/ 等等
内容
Installation
go get github.com/antlabs/pcopy
Quick start
package main
import (
“fmt”
“github.com/antlabs/pcopy”
)
type dst struct {
ID int
Result string
}
type src struct{
ID int
Text string
}
func main() {
d, s := dst{}, src{ID:3}
pcopy.Preheat(&dst{}, &src{}) // 一对类型只要预热一次
pcopy.Copy(&d, &s, pcopy.WithUsePreheat())
fmt.Printf("%#v\n", d)
}
copy slice
package main
import (
“fmt”
"github.com/antlabs/pcopy"
)
func main() {
i := []int{1, 2, 3, 4, 5, 6}
var o []int
pcopy.Preheat(&o, &i)
pcopy.Copy(&o, &i, pcopy.WithUsePreheat())
fmt.Printf("%#v\n", o)
}
copy map
package main
import (
“fmt”
"github.com/antlabs/pcopy"
)
func main() {
i := map[string]int{
“cat”: 100,
“head”: 10,
“tr”: 3,
“tail”: 44,
}
var o map[string]int
pcopy.Preheat(&o, &i)
pcopy.Copy(&o, &i, pcopy.WithUsePreheat())
fmt.Printf("%#v\n", o)
}
simplify business code development
经常看到,对同一个结构体的,有值更新操作,都是一堆手工 if 然后赋值的代码。不仅容易出错,还累。快使用 pcopy 解放双手。
type option struct {
Int int
Float64 float64
S string
}
func main() {
var a, b option
if b.Int != 0 {
a.Int = b.Int
}
if b.Float64 != 0.0 {
a.Float64 = b.Float64
}
if b.S != "" {
a.S = b.S
}
pcopy.Preheat(&a, &b) //只要预热一次
//可以约化成
pcopy.Copy(&a, &b, pcopy.WithUsePreheat())
}
benchmark
从零实现的 pcopy 相比 json 序列化与反序列化方式拥有更好的性能
goos: darwin
goarch: arm64
pkg: benchmark
Benchmark_Use_reflectValue_MiniCopy-8 334728 3575 ns/op
Benchmark_Use_reflectValue_DeepCopy-8 595302 1956 ns/op
Benchmark_Use_reflectValue_Copier-8 203574 5860 ns/op
Benchmark_Use_Ptr_jsoniter-8 821113 1477 ns/op
Benchmark_Use_Ptr_pcopy-8 3390382 354.0 ns/op
Benchmark_Use_Ptr_coven-8 1414197 848.7 ns/op
PASS
ok benchmark 9.771s
本项目压测
从下面的压测数据可以看到,基本提供了 4-10 倍的性能提升
goos: darwin
goarch: arm64
pkg: github.com/antlabs/pcopy
Benchmark_BaseMap_Unsafe_Pcopy-8 529747 2343 ns/op
Benchmark_BaseMap_miniCopy-8 62181 19212 ns/op
Benchmark_BaseMap_Reflect-8 93810 12756 ns/op
Benchmark_BaseSlice_Unsafe_Pcopy-8 2013764 595.1 ns/op
Benchmark_BaseSlice_miniCopy-8 154918 7728 ns/op
Benchmark_BaseSlice_Reflect-8 188720 6393 ns/op
Benchmark_BaseType_Unsafe_Pcopy-8 4872112 243.8 ns/op
Benchmark_BaseType_MiniCopy-8 517814 2278 ns/op
Benchmark_BaseType_Pcopy-8 635156 1886 ns/op
Benchmark_CompositeMap_Unsafe_Pcopy-8 486253 2409 ns/op
Benchmark_CompositeMap_miniCopy-8 229674 5173 ns/op
Benchmark_CompositeMap_Reflect-8 475243 2490 ns/op
Benchmark_GetLikeFavorited_Unsafe_Pcopy2-8 446907 2662 ns/op
Benchmark_GetLikeFavorited_Unsafe_Pcopy-8 470217 2572 ns/op
Benchmark_GetLikeFavorited_MiniCopy-8 85674 13989 ns/op
Benchmark_GetLikeFavorited_Reflect_Pcopy-8 121603 9856 ns/op
Benchmark_GetRedPoint_Unsafe_Pcopy-8 1626688 736.1 ns/op
Benchmark_GetRedPoint_MiniCopy-8 650004 1871 ns/op
Benchmark_GetRedPoint_Reflect_Pcopy-8 1669778 722.0 ns/op
Benchmark_Interface_Unsafe_Pcopy-8 2869022 421.3 ns/op
Benchmark_Interface_MiniCopy-8 413936 2704 ns/op
Benchmark_Interface_Pcopy-8 440250 2688 ns/op
Benchmark_Interface_BaseSlice_Unsafe_Pcopy-8 1266501 947.4 ns/op
Benchmark_Interface_BaseSlice_MiniCopy-8 141610 8422 ns/op
Benchmark_Interface_BaseSlice_Pcopy-8 203906 5917 ns/op
Benchmark_Ptr_BaseType1_Unsafe_Pcopy-8 910153 1310 ns/op
Benchmark_Ptr_BaseType1_Reflect_Pcopy-8 391117 3026 ns/op
Benchmark_Ptr_BaseSlice_Unsafe_Pcopy-8 698156 1704 ns/op
Benchmark_Ptr_BaseSlice_Reflect_Pcopy-8 219999 5415 ns/op
Benchmark_SliceWithStruct_Unsafe_Pcopy-8 1395982 860.3 ns/op
Benchmark_SliceWithStruct_miniCopy-8 163154 7298 ns/op
Benchmark_SliceWithStruct_Reflect_Pcopy-8 190728 6213 ns/op
Golang Go语言中深度拷贝pcopy,性能升级版本来了
更多关于Golang Go语言中深度拷贝pcopy,性能升级版本来了的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你这 codecov 42%有点难看啊, 我觉得低于 70%就别放了
更多关于Golang Go语言中深度拷贝pcopy,性能升级版本来了的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
感觉基于反射实现的一个最大的问题就是不支持私有字段,十分难受
后面再提高下,影响测试覆盖度的都是用 tmpl 生成的代码。
一直在用 copier
同用 copier
能支持多语言吗?
copier 从压测数据来看不太快。pcony 运行时间是 copier 的 1/16.
怎么理解?
有必要这么搞么,使用大量的反射来进行 deep copy 还是太重了吧
有和我一样直接序列化再反序列化完事的么……
那估计少有,哈哈
这么做只是为了可控性。能不停进行性能的提升。假如跳开这个库的话题,回到大家熟悉的服务端,我们可以用标准库快速一个 server 。如果要进行性能的提升,可能要进行一大量的定制开发(库作者的角度),比如 epoll+协程池+gc 优化。它背后的思路一样,开箱即用的东西,性能不好提升。
要支持的话也很简单,拿到这个字段的指针地址,后面直接修改就行。但是 pcopy 不会支持修改私有字段的。
针对帖子中提到的“Golang Go语言中深度拷贝deepcopy,性能升级版本来了”这一话题,作为IT领域的Go语言专家,以下是我的专业回复:
在Go语言中,深度拷贝(deepcopy)是一个重要的操作,尤其在处理复杂数据结构时,它能帮助开发者创建数据的完全独立副本,从而避免对原始数据的意外修改。近期,关于deepcopy性能升级版本的发布,无疑为Go语言开发者带来了福音。
性能升级通常意味着在保持原有功能的基础上,通过优化算法或数据结构等方式,提高了操作的执行效率。对于deepcopy而言,性能升级可能涉及减少内存分配、优化递归复制过程、减少反射使用等方面。这些改进将使得深度拷贝操作更加高效,尤其是在处理大规模数据集时,能够显著减少复制所需的时间和资源消耗。
建议开发者在升级前,仔细阅读新版本的发布说明,了解具体的性能改进点和可能存在的兼容性问题。在升级后,可以通过性能测试工具对应用程序进行基准测试,以确保新版本deepcopy在实际场景中的表现符合预期。