在Go中,哪个片段分配的对象较少?或者他们都使用相同数量的分配,如果是这样的话;为什么? (:
for i := 0; i < 10000000; i++ {
log.println("hello")
}
以下代码是否仅分配1个字符串?
const (
HELLO string = "hello"
)
for i := 0; i < 10000000; i++ {
log.println(HELLO)
}
答案 0 :(得分: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}
输出中{}
中的字符串标题显示指向字符数据的指针(&#34; hello&#34;),以及字符串的长度。
你可以看到整个程序中指向字符串数据的指针是相同的:字节数据&#34;你好&#34;无论循环计数是什么,无论它是硬编码字符串还是常量,都只引用一个内存地址(此处为4870353)。
语言规范本身并不保证这种行为,但是常量字符串实习是一种自然的优化,如果以任何明显不同的方式表现,那将是令人惊讶的。
答案 1 :(得分: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)
}
}
基准:
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列中,您可以获得有关分配大小及其编号的信息。在您的示例中,只有零,这意味着两个func都不进行任何分配:)