三种Golang数组拷贝方式及性能分析详解
作者:jiaxwu 发布时间:2023-07-13 07:54:27
标签:Golang,数组,拷贝
在Go语言中,我们可以使用for
、append()
和copy()
进行数组拷贝,对于某些对性能比较敏感且数组拷贝比较多的场景,我们可以会对拷贝性能比较关注,这篇文件主要是对比一下这三种方式的性能。
测试
测试条件是把一个64KB的字节数组分为64个块进行复制。
测试代码
package test
import (
"testing"
)
const (
blocks = 64
blockSize = 1024
)
var block = make([]byte, blockSize)
func BenchmarkFori(b *testing.B) {
a := make([]byte, blocks*blockSize)
for n := 0; n < b.N; n++ {
for i := 0; i < blocks; i++ {
for j := 0; j < blockSize; j++ {
a[i*blockSize+j] = block[j]
}
}
}
}
func BenchmarkAppend(b *testing.B) {
a := make([]byte, 0, blocks*blockSize)
for n := 0; n < b.N; n++ {
a = a[:0]
for i := 0; i < blocks; i++ {
a = append(a, block...)
}
}
}
func BenchmarkCopy(b *testing.B) {
a := make([]byte, blocks*blockSize)
for n := 0; n < b.N; n++ {
for i := 0; i < blocks; i++ {
copy(a[i*blockSize:], block)
}
}
}
测试结果
可以看到copy的性能是最好的,当然append的性能也接近copy,for性能较差。
BenchmarkFori-8 19831 52749 ns/op
BenchmarkAppend-8 775945 1478 ns/op
BenchmarkCopy-8 815556 1473 ns/op
原理分析
我们简单分析copy和append的原理。
copy
代码
可以看到最终都会调用memmove()
整块拷贝内存,而且是用汇编实现的,因此性能是最好的。
// slicecopy is used to copy from a string or slice of pointerless elements into a slice.
func slicecopy(toPtr unsafe.Pointer, toLen int, fromPtr unsafe.Pointer, fromLen int, width uintptr) int {
if fromLen == 0 || toLen == 0 {
return 0
}
n := fromLen
if toLen < n {
n = toLen
}
if width == 0 {
return n
}
size := uintptr(n) * width
if raceenabled {
callerpc := getcallerpc()
pc := funcPC(slicecopy)
racereadrangepc(fromPtr, size, callerpc, pc)
racewriterangepc(toPtr, size, callerpc, pc)
}
if msanenabled {
msanread(fromPtr, size)
msanwrite(toPtr, size)
}
if size == 1 { // common case worth about 2x to do here
// TODO: is this still worth it with new memmove impl?
*(*byte)(toPtr) = *(*byte)(fromPtr) // known to be a byte pointer
} else {
memmove(toPtr, fromPtr, size)
}
return n
}
append
代码
append最终会被编译期转换成以下代码,也是调用了memmove()
整块拷贝内存,因此其实性能是和copy差不多的。
s := l1
n := len(s) + len(l2)
// Compare as uint so growslice can panic on overflow.
if uint(n) > uint(cap(s)) {
s = growslice(s, n)
}
s = s[:n]
memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
来源:https://juejin.cn/post/7134957581801357348
0
投稿
猜你喜欢
- 假如你目前需要在Microsoft Access数据库中指示不存在数据,可以在“文本”或&l
- 本文实例讲述了PHP判断密码强度的方法。分享给大家供大家参考,具体如下:一、php页面$score = 0;if(!empty($_GET[
- 具体代码如下:Function ASTCreateFtpSite(IPAddress, RootDirectory,&n
- 首先将ORACLE 10g的安装光盘放入光驱,如果自动运行,一般会出现如图1安装界面: 图1 单击“开始安装”,就可以安装ORACLE 10
- python实现阶乘-基础版本什么是阶乘呢?在数学运算中n!表示n的阶乘,用数学公式表示为:n!=1*2*3*....*(n-1)*n下面提
- 代码如下:--CAST 和 CONVERT 函数 Percentage DECLARE @dec decimal(5,3), @var va
- 1. 打开FrontPage 2003,点击“文件→新建→新建网站→其他网站模板”,然后选择“数据库界面向导”,给定网站路径后,单击[确定]
- 一.链接打开方式1、新窗口打开优点:用户点链接的时候,当前浏览的内容不会被替换,不需要通过前进、后退去看自己看过的内容;缺点:访问一会,就会
- chat.html <html> <head><title>asp之家-简单聊天&l
- 阅读:Dreamweaver量身打造Wordpress留言板(一)虽然说在Dreamweaver量身打造Wordpress留言板(二)这一篇
- 用比较笨的方法来做abc ="AlkjA;lkjlkjAlkAkjAlkjAAAA" if instr(abc,&quo
- var getWindow = function(obj) { var&nbs
- 本文实例讲述了PHP判断是否微信访问的方法。分享给大家供大家参考,具体如下:在开发中有时需要禁止或者仅允许微信浏览器进行访问,则此时就需要对
- 虽然今年名义上已经不再管人了,但也不得不掺和进很多人事,这里想简单说说,即使不能帮助这个行业的从业者规划职业道路,也算是把之前摸过的路小结一
- 曾经有许多创造性的logo设计案例,logo设计资源和logo设计指导张贴在互联网的各个角落。这些帮助会为你的logo设计创造一个功能强大的
- 这几天刚刚做了这个东西,有网友问到,所以分享一下。ie6、firefox2 通过,麻烦有ie7的网友测试一下,由于有其他代码,剖析出来麻烦,
- 分页设计我们经常会见到,这里有30个分页设计,以供大家欣赏欣赏借鉴。
- 插件很多从事互联网行业或者开发的人员来不是很陌生,wordpress之所以为什么那么受欢迎,很大部分是因为他的强大的插件库,还要譬如就是大家
- 站长们是不是还在为空间不支持域名绑定到子目录而发愁呢?买了个便宜也不错的空间,用的还满意,准备再开几个网站,却发现空间程序太落后,无法支持域
- 我一直使用Microsoft的FrontPage 98来开发ASP/ADO之类的Internet数据库应用程序。现在我听说许多人都非常信奉采