2016-07-13 46 views
2

Inスニペットではオブジェクトの割り当てが少なくなりますか?そうであれば、どちらも同じ量の割り当てを使用しますか?どうして? (: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"は、ループカウントに関係なく、正確に1つのメモリアドレス(ここでは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) 
    } 
} 

ベンチマーク:あなたのケースでは、コードは次のようになります

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フラグです。それがなければ、ベンチマークではベンチマーク時間だけがわかります。1回の操作あたりの割り当て数と平均割り当てサイズに関する情報は得られません。ベンチマークの

出力:あなたは配分の大きさとその数についての情報を持っている最後の2列に

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 

。あなたの例では、両方の関数が割り当てをしないことを意味するゼロだけがあります。)

関連する問題