这个问题是关于 访问 数组和切片 元素 的速度,而不是关于将它们作为参数传递给函数的效率。
我希望在大多数情况下, 数组 比 切片
更快,因为切片是描述数组连续部分的数据结构,因此访问切片的元素(间接访问其基础数组的元素)时可能涉及额外的步骤。
因此,我编写了一个小测试来对一批简单操作进行基准测试。有4个基准测试功能,前两个测试一个 全局 切片和一个全局数组,其他两个测试一个 本地
切片和一个本地数组:
var gs = make([]byte, 1000) // Global slice
var ga [1000]byte // Global array
func BenchmarkSliceGlobal(b *testing.B) {
for i := 0; i < b.N; i++ {
for j, v := range gs {
gs[j]++; gs[j] = gs[j] + v + 10; gs[j] += v
}
}
}
func BenchmarkArrayGlobal(b *testing.B) {
for i := 0; i < b.N; i++ {
for j, v := range ga {
ga[j]++; ga[j] = ga[j] + v + 10; ga[j] += v
}
}
}
func BenchmarkSliceLocal(b *testing.B) {
var s = make([]byte, 1000)
for i := 0; i < b.N; i++ {
for j, v := range s {
s[j]++; s[j] = s[j] + v + 10; s[j] += v
}
}
}
func BenchmarkArrayLocal(b *testing.B) {
var a [1000]byte
for i := 0; i < b.N; i++ {
for j, v := range a {
a[j]++; a[j] = a[j] + v + 10; a[j] += v
}
}
}
我多次运行测试,这是典型的输出(go test -bench .*
):
BenchmarkSliceGlobal 300000 4210 ns/op
BenchmarkArrayGlobal 300000 4123 ns/op
BenchmarkSliceLocal 500000 3090 ns/op
BenchmarkArrayLocal 500000 3768 ns/op
分析结果:
如我所料,访问全局片比访问全局数组要慢一些:
4210
vs 4123
ns / op
但是访问本地切片比访问本地阵列要快得多:
3090
vs 3768
ns / op
我的问题是: 这是什么原因?
笔记
我尝试更改以下内容,但没有改变结果:
byte
和int
)比较了AMD64组装两者的BenchmarkArrayLocal
和BenchmarkSliceLocal
(太长,不适合在这个岗位):
阵列版本a
实际上是在每次阵列访问操作中多次从内存加载地址:
LEAQ "".a+1000(SP),BX
从存储器加载一次后,分片版本仅在寄存器上计算:
LEAQ (DX)(SI*1),BX
这不是决定性的,但可能是原因。原因是这两种方法实际上是完全相同的。另一个值得注意的细节是数组版本调用runtime.duffcopy
,这是一个相当长的汇编例程,而切片版本则没有。
这章我们开始剖析 容器, 它是可以包含大量条目(item)的数据结构, 例如数组、切片和 map。从这看到 Go 明显受到 Python 的影响。 以 [] 符号标识的数组类型几乎在所有的编程语言中都是一个基本主力。Go 语言中的数组也是类似的,只是有一些特点。Go 没有 C 那么灵活,但是拥有切片(slice)类型。这是一种建立在 Go 语言数组类型之上的抽象,要想理解切片我们必须先理解数组。数
问题内容: 在php中,我经常需要使用数组来映射变量…但是我似乎无法在一个内衬中做到这一点。cf范例: 这是一个小问题,但有时会不时出现错误……我不喜欢这样的事实,我什么都不用使用变量;) 问题答案: 我真的不会去理会这个额外的变量。但是,如果需要,也可以在使用后将其从内存中删除: 或者,您可以编写一个小函数: 并使用以下命令调用: 现在应该自动销毁该阵列。
问题内容: Core Audio具有C API,可将一些数据复制到您提供的内存中。在一种情况下,我需要传递一个指向AudioBufferList的指针,该指针定义为: UInt32标识缓冲区的数量,并且实际缓冲区紧随其后。 我可以成功获得此: 我无法识别(AudioBuffer)语法,但我认为它并不重要- 我认为括号会被忽略,mBuffers只是一个AudioBuffer,由我自己完成指针数学运算
创建: arr1 := new([len]type) slice1 := make([]type, len) 初始化: arr1 := [...]type{i1, i2, i3, i4, i5} arrKeyValue := [len]type{i1: val1, i2: val2} var slice1 []type = arr1[start:end] (1)如何截断数组或者切片的最后一个元素:
问题内容: 我是Python和numpy的新手。我已经弄清楚如何对一维序列进行切片:,并访问数组中的元素:。 尝试类似(numpy数组在哪里)的操作不会给我前两行和一列,而是会重复前两行。我刚才做了什么,以及如何沿着另一个维度进行切片? 问题答案: 如果使用,这很容易: 或者如果您想要0, 您将得到相同的结果。 *请注意,这实际上是内置类型的名称。通常,我建议给您的对象一个不同的“名称”。 换句话
我是一个编程新手。我在go编程书中读到过,片由三部分组成:指向数组的指针、长度和容量。 我感到困惑的零切片(切片没有底层数组指向,len=0,cap=0),非零切片只有len=0,cap=0和空切片。 谁能告诉我零和空切片是否是一回事?如果它们都不同,那么请告诉这两者之间的区别是什么? 如何测试一个切片是否为空? 另外,指针在长度和容量为零的非nil片中保留什么值?