去lang字符串常量

时间:2014-02-12 11:05:21

标签: go benchmarking

内联字符串和Go中使用的常量字符串之间是否存在差异,还是由编译器完全优化?

100B迭代的示例基准代码:

package main

import "fmt"
import "time"
import "log"

func main() {
    // String
    start := time.Now()
    for i := 0; i < 100000000; i++ {
        x := "My String"
        if i % 1000000 == 0{
            fmt.Printf(x)
        }
    }
    elapsed := time.Since(start)
    log.Printf("\nTook %s", elapsed)

    // Constant
    start2 := time.Now()
    const MY_STRING = "My String 2"
    for i := 0; i < 100000000; i++ {
        x := MY_STRING
        if i % 1000000 == 0 {
            fmt.Printf(x)
        }
    }

    elapsed2 := time.Since(start2)
    log.Printf("\nTook %s", elapsed2)

    // Proof that the timer does work :)
    start3 := time.Now()
    time.Sleep(100 * time.Millisecond)
    elapsed3 := time.Since(start3)
    log.Printf("\nTook %s", elapsed3)

}

输出:

My StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy String2009/11/10 23:00:00 
Took 0
My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My String 22009/11/10 23:00:00 
Took 0
2009/11/10 23:00:00 
Took 100ms

Program exited.

3 个答案:

答案 0 :(得分:8)

两者之间的编译代码没有区别,所以它不应该影响你的结果。请采用以下示例文件:

package foo

func foo() string {
    x := "Foo"
    return x
}

const MY_STRING = "Bar"

func bar() string {
    x := MY_STRING
    return x
}

汇编程序输出显示两个函数是相同的(以不同的字符串常量为模):

$ go tool 6g -S foo.go

--- prog list "foo" ---
0000 (foo.go:3) TEXT    foo+0(SB),$0-16
0001 (foo.go:3) FUNCDATA $0,gcargs·0+0(SB)
0002 (foo.go:3) FUNCDATA $1,gclocals·0+0(SB)
0003 (foo.go:3) TYPE    ~anon0+0(FP){string},$16
0004 (foo.go:4) LEAQ    go.string."Foo"+0(SB),BX
0005 (foo.go:4) MOVQ    (BX),CX
0006 (foo.go:4) MOVQ    8(BX),BP
0007 (foo.go:5) MOVQ    CX,~anon0+0(FP)
0008 (foo.go:5) MOVQ    BP,~anon0+8(FP)
0009 (foo.go:5) RET     ,

--- prog list "bar" ---
0010 (foo.go:10) TEXT    bar+0(SB),$0-16
0011 (foo.go:10) FUNCDATA $0,gcargs·1+0(SB)
0012 (foo.go:10) FUNCDATA $1,gclocals·1+0(SB)
0013 (foo.go:10) TYPE    ~anon0+0(FP){string},$16
0014 (foo.go:11) LEAQ    go.string."Bar"+0(SB),BX
0015 (foo.go:11) MOVQ    (BX),CX
0016 (foo.go:11) MOVQ    8(BX),BP
0017 (foo.go:12) MOVQ    CX,~anon0+0(FP)
0018 (foo.go:12) MOVQ    BP,~anon0+8(FP)
0019 (foo.go:12) RET     ,

正如您所看到的,在两种情况下,字符串常量都以相同的方式加载。

答案 1 :(得分:3)

没有真正的区别。 如果您测量它,您将看到两者以相同的速度运行。因为Go中的所有字符串都是常量,所以这不应该是一个惊喜。

如果您真的参与了这种微优化,请查看生成的汇编程序

  

去工具6g -S main.go

答案 2 :(得分:0)

好的,问题不在于代码,而是与http://golang.org/有关,他们执行Web代码的方式。在本地,使用字符串常量似乎更快:

> go run bench_string_constant_golang.go

My StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy Strin
gMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy Stri
ngMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy Str
ingMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy St
ringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy S
tringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy
StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy
 StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringM
y StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy String
My StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy Strin
gMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy StringMy Stri
ngMy StringMy String2014/02/12 12:07:21
Took 1.6400938s

My String 2My String 2My String 2My String 2My String 2My String 2My String 2My
String 2My String 2My String 2My String 2My String 2My String 2My String 2My Str
ing 2My String 2My String 2My String 2My String 2My String 2My String 2My String
 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2M
y String 2My String 2My String 2My String 2My String 2My String 2My String 2My S
tring 2My String 2My String 2My String 2My String 2My String 2My String 2My Stri
ng 2My String 2My String 2My String 2My String 2My String 2My String 2My String
2My String 2My String 2My String 2My String 2My String 2My String 2My String 2My
 String 2My String 2My String 2My String 2My String 2My String 2My String 2My St
ring 2My String 2My String 2My String 2My String 2My String 2My String 2My Strin
g 2My String 2My String 2My String 2My String 2My String 2My String 2My String 2
My String 2My String 2My String 2My String 2My String 2My String 2My String 2My
String 2My String 2My String 2My String 2My String 2My String 2My String 2My Str
ing 2My String 2My String 2My String 2My String 2My String 22014/02/12 12:07:23
Took 1.6220928s

2014/02/12 12:07:23
Took 100.0057ms