我有以下的测试代码:转:使用指针的json编码结构比使用副本更慢?
package main
import (
"fmt"
"testing"
"encoding/json"
)
type Coll1 struct {
A string
B string
C string
}
type Coll2 struct {
A *string
B *string
C *string
}
var as = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
var bs = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
var cs = "ccccccccccccccccccccccccccccccccc"
func testBM1(b *testing.B) {
for i := 0; i<b.N; i++ {
json.Marshal(Coll1{as,bs,cs})
}
}
func testBM2(b *testing.B) {
for i := 0; i<b.N; i++ {
json.Marshal(Coll2{&as,&bs,&cs})
}
}
func main() {
fmt.Println(testing.Benchmark(testBM1))
fmt.Println(testing.Benchmark(testBM2))
}
我希望第二种情况下,因为它是采用指针,因此它不具有复制串跑得更快,但实际上它在约4250纳秒运行/ op,其中第一个运行在2800 ns/op附近。任何人都可以阐明为什么这可能是什么?
编辑:Darshan Computing建议,这甚至可以适用于嵌入式结构。一个简单的测试证实了这一点:
package main
import (
"fmt"
"testing"
"encoding/json"
)
type Coll1 struct {
A,B,C string
}
type Coll1Outer struct {
A,B,C Coll1
}
type Coll2Outer struct {
A,B,C *Coll2
}
type Coll2 struct {
A,B,C *string
}
var as = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
var bs = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
var cs = "ccccccccccccccccccccccccccccccccc"
func testBM1(b *testing.B) {
for i := 0; i<b.N; i++ {
c := Coll1Outer{ Coll1{as,bs,cs},
Coll1{as,bs,cs},
Coll1{as,bs,cs} }
json.Marshal(c)
}
}
func testBM2(b *testing.B) {
for i := 0; i<b.N; i++ {
c := Coll2Outer{ &Coll2{&as,&bs,&cs},
&Coll2{&as,&bs,&cs},
&Coll2{&as,&bs,&cs} }
json.Marshal(c)
}
}
func main() {
fmt.Println(testing.Benchmark(testBM1))
fmt.Println(testing.Benchmark(testBM2))
}
对我来说这示出了非指针结构取约12毫秒/运算,而一个具有指针需要13毫秒/ OP。没有太大的区别,但有趣的是该物业仍然有效。
我重写了代码以充分利用内置的基准测试功能(请参阅http://play.golang.org/p/90fYFCSjN9),第一次获得了3729 ns/op,第二次获得了4600 ns/op win8_64,仍然看起来不对,但值更接近。 – Intermernet
而且,如果我用'_ = fmt.Sprintf'调用替换'json.Marshal'调用,则分别得到11990 ns/op和7098 ns/op(使指针快70%)。 json.Marshall函数在使用指针时会降低速度。 – Intermernet
经过多一点研究后,我认为这是因为'encoding/json'中的'marshal'函数在输入接口调用'reflect.ValueOf()'(http://golang.org/src/pkg/encoding/json/ encode.go?s = 7722:7964#L230),如果需要查找由指针表示的值的类型,可能会比较慢,而不是直接在值itslef上。只是一个猜测。 – Intermernet