2016-07-13 109 views
2

在哪个片段分配较少的对象?或者他们都使用相同数量的分配,如果是的话;为什么? (:常量在Go中如何工作?

for i := 0; i < 10000000; i++ { 
     log.println("hello") 
    } 

请问下面的代码仅分配1串

const (
    HELLO string = "hello" 
) 

for i := 0; i < 10000000; i++ { 
    log.println(HELLO) 
} 
+2

我很确定编译器将内联字符串,而不是分配它X次。如果一种语言做到了,我就不会使用它。 – squiguy

+1

将两个示例的程序集输出与'go tool compile -S' –

回答

5

这是你的程序的适应打印出在这两种情况下的基本字符串表示

package main 

import (
    "fmt" 
    "reflect" 
    "unsafe" 
) 

const (
    Hello string = "hello" 
) 

func main() { 
    for i := 0; i < 3; i++ { 
     a := "hello" 
     sh := (*reflect.StringHeader)(unsafe.Pointer(&a)) 
     fmt.Println(a, " ", *sh) 
    } 

    fmt.Println() 

    for i := 0; i < 3; i++ { 
     a := Hello 
     sh := (*reflect.StringHeader)(unsafe.Pointer(&a)) 
     fmt.Println(a, " ", *sh) 
    } 
} 

这里的?输出:

hello {4870353 5} 
hello {4870353 5} 
hello {4870353 5} 

hello {4870353 5} 
hello {4870353 5} 
hello {4870353 5} 

输出中的{}中的字符串标题显示了指向字符数据(“hello”)的指针和字符串的长度。

您可以看到指向字符串数据的指针在整个程序中都是相同的:字节数据“hello”恰好在一个内存地址(此处为4870353)处引用,无论循环次数如何,无论它是一个硬编码的字符串或常量。

语言规范本身并不保证这种行为,但常量字符串实习是一种自然优化,如果以任何显着不同的方式行事,那将是令人惊讶的。

1

寻找Go是否进行一些分配的最简单方法是编写基准。在你的情况的代码可能看起来像:

package sof 

import "log" 

const (
    HELLO = "hello" 
) 

func forString(max int) { 
    for i := 0; i < max; i++ { 
     logMsg("hello", false) 
    } 
} 

func forConst(max int) { 
    for i := 0; i < max; i++ { 
     logMsg(HELLO, false) 
    } 
} 

func logMsg(msg string, stdOut bool) { 
    if stdOut { 
     log.Println(msg) 
    } 
} 

和Benchmark:

package sof 

import "testing" 

func BenchmarkForString(b *testing.B) { 
    for i := 0; i < b.N; i++ { 
     forString(i) 
    } 
} 

func BenchmarkForConst(b *testing.B) { 
    for i := 0; i < b.N; i++ { 
     forConst(i) 
    } 
} 

然后,你可以运行基准:

go test -bench=. -benchmem 

很重要的是-benchmem标志。如果没有它,你的基准测试只会告诉你关于基准时间的信息 - 你不会得到关于每个操作的分配数量和平均分配大小的信息。

输出的基准:

testing: warning: no tests to run 
BenchmarkForString-4  100000  133551 ns/op   0 B/op   0 allocs/op 
BenchmarkForConst-4  100000  128585 ns/op   0 B/op   0 allocs/op 
PASS 
ok  .../sof 26.475s 

在您对分配的大小和其编号的信息最后2列。在你的例子中只有零,这意味着这两个funcs不作任何分配:)