为什么通过go插件调用函数比直接调用函数更快



我想对go插件进行基准测试,看看性能差异是什么。所以我用以下代码制作了一个main.go文件:

package main
import (
"math/rand"
"strings"
)
// RandString generates and returns a random 50 character string
func RandString(n int) string {
rand.Seed(int64(n))
chars := []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz" +
"0123456789")
var b strings.Builder
for i := 0; i < 50; i++ {
b.WriteRune(chars[rand.Intn(len(chars))])
}
return b.String()
}

然后我把它变成一个plugin.so文件。

go build -buildmode=plugin -o plugin.so main.go

接下来,我编写了两个基准函数来测试内联运行函数与通过go插件运行函数的性能。

// BenchmarkRandString tests generating a random string without a go plugin
func BenchmarkRandString(b *testing.B) {
for i := 0; i < b.N; i++ {
RandString(rand.Int())
}
}
// BenchmarkPluginRandString tests generating a random string with a go plugin
func BenchmarkPluginRandString(b *testing.B) {
plug, err := plugin.Open("./plugin.so")
if err != nil {
panic(err)
}
randString, err := plug.Lookup("RandString")
if err != nil {
panic(err)
}
randFunc, ok := randString.(func(n int) string)
if !ok {
panic("unexpected type from module symbol")
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
randFunc(rand.Int())
}
}

正如我所期望的,插件有点慢,但没有太多

BenchmarkRandString-12 128064 8600 ns/op
BenchmarkPluginRandString-12 132007 8713 ns/op

接下来我想再添加两个基准测试,所以我添加了另一个函数来生成一个随机整数,并以与以前相同的方式构建插件。

// RandInt uses math/rand to return a random integer
func RandInt() int {
return rand.Int()
}

然后,我的新基准函数在前两个基准函数的基础上添加了。

// BenchmarkRandInt tests math/rand for generating random integers without a go plugin
func BenchmarkRandInt(b *testing.B) {
for i := 0; i < b.N; i++ {
RandInt()
}
}
// BenchmarkPluginRandInt uses a go plugin and tests math/rand for generating random integers
func BenchmarkPluginRandInt(b *testing.B) {
plug, err := plugin.Open("./plugin.so")
if err != nil {
panic(err)
}
randInt, err := plug.Lookup("RandInt")
if err != nil {
panic(err)
}
randFunc, ok := randInt.(func() int)
if !ok {
panic("unexpected type from module symbol")
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
randFunc()
}
}

现在,当我再次运行基准测试时,我得到以下结果:

BenchmarkRandInt-12 77320668 13.2 ns/op
BenchmarkPluginRandInt-12 76371756 13.9 ns/op

我可以反复运行基准测试,BenchmarkRandString-12总是比BenchmarkPluginRandString-12慢一点,这不是我所期望的。为什么在这样的基准测试中go插件的功能稍微快一点?

我有一个Github项目,其中包含了我在这里使用的所有源代码:https://github.com/uberswe/goplugins/tree/4825172e011da9578553d113bac7933ca9ecd038

使用"插件";函数是它的加载和类型断言。完成后,与应用程序中定义的函数相比,不应该有性能损失。

如此微小的偏差可能是Go内部内存管理和垃圾收集的结果。例如,如果在您的main_test.go文件中,我将BenchmarkPluginRandString()移动到BenchmarkRandString()之上,则基准测试结果为"0";"反转":CCD_ 4变得稍微慢一些。

为了消除这种不确定性因素,您可以尝试孤立地运行基准测试,例如,使用一次只运行一个

go test -bench BenchmarkRandString

go test -bench BenchmarkPluginRandString

多次这样做,并计算平均值。这样就没有明显的区别。

最新更新