pointers - 基准测试时指针接收器不比值接收器快

标签 pointers go

这是我正在测试的代码,我希望看到基准测试时,基于指针的 addDataPointer 比基于​​ addData 值的函数执行得更快。为什么两者在性能上没有显着变化?

package main

import "fmt"

type BigStruct struct {
    name string
    data []byte
}

func addData(s BigStruct) BigStruct {
    s.data = append([]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}, s.data...)
    return BigStruct{name: s.name, data: s.data}
}

func (s *BigStruct) addDataPointer() {
    s.data = append([]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}, s.data...)
}

func main() {
    a := BigStruct{name: "greg", data: []byte("abc")}
    b := &BigStruct{name: "greg", data: []byte("abc")}
    fmt.Println(addData(a))
    b.addDataPointer()
    fmt.Println(*b)
}

func BenchmarkBigLenPointer(b *testing.B) {
    for i := 0; i < b.N; i++ {
        big := &BigStruct{name: "greg", data: []byte(strings.Repeat("test1234", 1024))}
        big.addDataPointer()
    }
}

func BenchmarkBigLen(b *testing.B) {
    for i := 0; i < b.N; i++ {
        big := BigStruct{name: "greg", data: []byte(strings.Repeat("test1234", 1024))}
        addData(big)
    }

最佳答案

您的基准函数测量 for 循环内的任何内容,例如:

    big := &BigStruct{name: "greg", data: []byte(strings.Repeat("test1234", 1024))}
    big.addDataPointer()

和:

    big := BigStruct{name: "greg", data: []byte(strings.Repeat("test1234", 1024))}
    addData(big)

因此您还对 strings.Repeat() 进行了基准测试,它为您提供了一个很长的 string 值,并且您还将其转换为 []byte,它会复制这个冗长的 string

这些的执行时间比您的 addDataPointer() 方法和 addData() 函数的执行时间要长得多。

将转换和 strings.Repeat() 调用移到 for 循环之外,如下所示:

func BenchmarkBigLenPointer(b *testing.B) {
    s := []byte(strings.Repeat("test1234", 1024))
    for i := 0; i < b.N; i++ {
        big := &BigStruct{name: "greg", data: s}
        big.addDataPointer()
    }
}

func BenchmarkBigLen(b *testing.B) {
    s := []byte(strings.Repeat("test1234", 1024))
    for i := 0; i < b.N; i++ {
        big := BigStruct{name: "greg", data: s}
        addData(big)
    }
}

现在可以更准确地测量您的方法和函数的时间。但即使您对其进行基准测试,您也会得到基准测试结果,表明 addData()addDataPointer() 的执行时间非常接近。

对此的解释是,在函数的情况下,您传递一个包含字节 slice 的结构值。 Go 中的 slice 是小型描述符(类似于 header 的结构),它不包含 slice 的元素,而仅包含指向支持数组的指针。所以 slice 值的大小是相同的,不管它的长度(元素的数量)如何。要查看 slice header 中的内容,请查看 reflect.SliceHeader类型。

所以函数的开销很小,这可能会增加它的执行时间,但另一方面指针方法需要取消引用指针,这会增加它的执行时间。最后,他们非常接近。在这种情况下,差别不大。

关于pointers - 基准测试时指针接收器不比值接收器快,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40328658/

相关文章:

string - 定义一个没有 hex.DecodeString 的 []byte

go - 如何将结构作为参数传递给 xml-rpc

go - 如何像 Javascript 的 Joi 一样验证 Go 对象数据?

c - 访问全局整数数组时出现段错误

c - 一个用字符指针创建字符串但在途中出错的实验

c++ - 如何检查指针是否指向虚拟基类而不是 C++ 中的子类?

Go:对多重赋值的困惑

go - 带 channel 的 WaitGroup

c - 递归调用中head变为0后会发生什么?

c++ - 在类 : good programming practice? 中存储指针引用