2013-05-31 13 views
2

我有以下的测试代码:转:使用指针的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。没有太大的区别,但有趣的是该物业仍然有效。

+1

我重写了代码以充分利用内置的基准测试功能(请参阅http://play.golang.org/p/90fYFCSjN9),第一次获得了3729 ns/op,第二次获得了4600 ns/op win8_64,仍然看起来不对,但值更接近。 – Intermernet

+1

而且,如果我用'_ = fmt.Sprintf'调用替换'json.Marshal'调用,则分别得到11990 ns/op和7098 ns/op(使指针快70%)。 json.Marshall函数在使用指针时会降低速度。 – Intermernet

+1

经过多一点研究后,我认为这是因为'encoding/json'中的'marshal'函数在输入接口调用'reflect.ValueOf()'(http://golang.org/src/pkg/encoding/json/ encode.go?s = 7722:7964#L230),如果需要查找由指针表示的值的类型,可能会比较慢,而不是直接在值itslef上。只是一个猜测。 – Intermernet

回答

1

我注意到NS/OP的最大百分比差当我设置asbs,并cs"a""b""c",分别。当我增加字符串的长度时,它们彼此接近。他们似乎总是大约1000 ns/op不同。

所以我相信所有这一切都是我的机器需要1000 ns(1450)反映并遵循指针。在前面传递一个较小的结构似乎并不能抵消这种影响,因为一旦遵循指针,Marshal仍然会在生成和返回等效的JSON的过程中在内部传递数据。

+0

吻合。这很有道理,我没有想过它会需要某种反思。对于一个更大的嵌入式结构体系(多层深度,许多领域),我认为假设指针在这种情况下通常会更快? –

+0

@MediocreGopher我的猜测是即使对于复杂的结构也可以使用相同的模式,但是如果您测试了结果,我肯定会对结果感兴趣。 –

+0

我编辑了我的原始问题,为嵌入式结构提供了一个基本的测试用例,看起来你是对的。我仍然很好奇为什么反思指针需要很长时间。我认为即使是非指针类型也必须进行反射,是否非指针不一定需要额外的“跳跃”来获取真实的数据? –