ゴーコンディションとその奇妙さ

ループ内の条件をチェックするこれら2つのオプションは、パフォーマンスが同等だと思いますか?



if a > b && c*2 > d { .... } //  if a <= b { continue; } if c*2 > d { .... }
      
      





すべては「脳の準備」から始まり、最大偶数の整数の配列[-x .... x]による最適な検索の例を示す必要がありました。 偶数を見つけるために、1による論理乗算を使用すると、パフォーマンスがどれほど向上するのか疑問に思いました。



 //       0 value & 1 == 0 //vs   value % 2 == 0
      
      





Goでの私のプログラミングエクスペリエンスはそれほど大きくなく、1年半半ほどでしたが、頻繁に使用しましたが、純粋に実用的な目的で使用しました(多分、負荷の高いhttpサービスに関連する1つのプロジェクトを除く)。 GoLandを開き、簡単なテストを作成します



 package main import ( "fmt" "log" "math" "math/rand" "time" ) const size = 100000000 //math.MaxInt32*2 type Result struct { Name string Duration time.Duration Value int32 } func main() { log.Println("initial array capacity: " + fmt.Sprint(size)) var maxValue int32 //       //  .   ,   //       //   ,      for maxValue = 128; maxValue < math.MaxInt32/2+1; maxValue = maxValue * 2 { test(maxValue) } } func test(maxValue int32) { log.Println("max threshold: " + fmt.Sprint(maxValue)) arr := make([]int32, size) for i := range arr { arr[i] = rand.Int31n(maxValue) //         sign := rand.Intn(2) if sign == 1 { arr[i] = -arr[i] } } //   "  " result := maxEvenDividing("maxEvenDividing", arr) log.Printf(result.Name+"\t result: "+fmt.Sprint(result.Value)+"\t\tduration %s", result.Duration) //   "" result = maxEvenConjunction("maxEvenConjunction", arr) log.Printf(result.Name+"\t result: "+fmt.Sprint(result.Value)+"\t\tduration %s", result.Duration) } func maxEvenDividing(name string, arr []int32) Result { start := time.Now() var current int32 = math.MinInt32 for _, value := range arr { if value > current && value%2 == 0 { current = value } } duration := time.Since(start) result := Result{name, duration, current} return result } func maxEvenConjunction(name string, arr []int32) Result { start := time.Now() var current int32 = math.MinInt32 for _, value := range arr { if value > current && value&1 == 0 { current = value } } duration := time.Since(start) result := Result{name, duration, current} return result }
      
      





しきい値が高いほど、パフォーマンスに関して変動が頻繁に現れるという結果が得られます。



比較する
max threshold: 128

maxEvenDividing result: 126 duration 116.0067ms

maxEvenConjunction result: 126 duration 116.0066ms



max threshold: 16384

maxEvenDividing result: 16382 duration 115.0066ms

maxEvenConjunction result: 16382 duration 111.0064ms



......



max threshold: 8388608

maxEvenDividing result: 8388606 duration 109.0063ms

maxEvenConjunction result: 8388606 duration 109.0062ms



max threshold: 16777216

maxEvenDividing result: 16777214 duration 108.0062ms

maxEvenConjunction result: 16777214 duration 109.0062ms



max threshold: 33554432

maxEvenDividing result: 33554430 duration 114.0066ms

maxEvenConjunction result: 33554430 duration 110.0063ms



max threshold: 67108864

maxEvenDividing result: 67108860 duration 111.0064ms

maxEvenConjunction result: 67108860 duration 109.0062ms



max threshold: 134217728

maxEvenDividing result: 134217726 duration 108.0062ms

maxEvenConjunction result: 134217726 duration 109.0063ms



max threshold: 268435456

maxEvenDividing result: 268435446 duration 111.0063ms

maxEvenConjunction result: 268435446 duration 110.0063ms







この場合、異なるしきい値に対して異なるテストデータセットがあり、プロセッサー負荷(i5-2540Mラップトップで)が20..30%前後で変化し、GoLandの下から実行されるアプリケーションが占有するメモリーが平均で約813 MBであることは明らかです-これも結果の信頼性に影響するため、テストスイートの保存をディスクに実装し、各しきい値のすべてのテストを相互に分離して実行する必要があります。



最小限の費用でこれらすべてを実装する方法を考えて、条件チェックを自動的に修正します



 if value > current && value&1 == 0 { current = value }
      
      









 if value <= current { continue; } if value&1 == 0 { current = value }
      
      





私は再びテストを実行します...そして何かを理解することをやめます



実行に費やされる時間は、既にパーセント/パーセントの割合ではなく、10..15%ずつ異なりますが、さらに2つのテストを追加します。



 func maxEvenDividing2(name string, arr []int32) Result { start := time.Now() var current int32 = math.MinInt32 for _, value := range arr { if value <= current { continue } if value%2 == 0 { current = value } } duration := time.Since(start) result := Result{name, duration, current} return result } func maxEvenConjunction2(name string, arr []int32) Result { start := time.Now() var current int32 = math.MinInt32 for _, value := range arr { if value <= current { continue } if value&1 == 0 { current = value } } duration := time.Since(start) result := Result{name, duration, current} return result }
      
      





私はこの写真を起動して取得します:
初期アレイ容量:100000000



最大しきい値:128

maxEvenDividing結果:126持続時間116.0066ms

maxEvenDividing2結果:126期間79.0045ms

maxEvenConjunctionの結果:126持続時間114.0065ms

maxEvenConjunction2の結果:126期間83.0048ms



最大しきい値:256

maxEvenDividing結果:254期間111.0063ms

maxEvenDividing2結果:254持続時間77.0044ms

maxEvenConjunctionの結果:254期間110.0063ms

maxEvenConjunction2の結果:254期間80.0046ms



最大しきい値:512

maxEvenDividingの結果:510期間114.0066ms

maxEvenDividing2の結果:510期間80.0045ms

maxEvenConjunctionの結果:510期間110.0063ms

maxEvenConjunction2の結果:510期間80.0046ms



最大しきい値:1024

maxEvenDividing結果:1022持続時間109.0063ms

maxEvenDividing2結果:1022期間77.0044ms

maxEvenConjunctionの結果:1022期間111.0063ms

maxEvenConjunction2結果:1022期間81.0047ms



最大しきい値:2048

maxEvenDividing結果:2046期間114.0065ms

maxEvenDividing2結果:2046期間79.0045ms

maxEvenConjunctionの結果:2046期間113.0065ms

maxEvenConjunction2の結果:2046期間81.0046ms



最大しきい値:4096

maxEvenDividing結果:4094期間114.0065ms

maxEvenDividing2結果:4094期間80.0046ms

maxEvenConjunctionの結果:4094期間111.0063ms

maxEvenConjunction2の結果:4094期間78.0045ms



最大しきい値:8192

maxEvenDividingの結果:8190期間107.0062ms

maxEvenDividing2結果:8190期間77.0044ms

maxEvenConjunctionの結果:8190期間111.0063ms

maxEvenConjunction2の結果:8190期間77.0044ms



最大しきい値:16384

maxEvenDividing結果:16382期間109.0063ms

maxEvenDividing2結果:16382期間77.0044ms

maxEvenConjunctionの結果:16382期間108.0062ms

maxEvenConjunction2の結果:16382期間77.0044ms



最大しきい値:32768

maxEvenDividingの結果:32766の持続時間112.0064ms

maxEvenDividing2結果:32766期間77.0044ms

maxEvenConjunctionの結果:32766の持続時間109.0062ms

maxEvenConjunction2の結果:32766の持続時間78.0045ms



最大しきい値:65536

maxEvenDividingの結果:65534期間109.0062ms

maxEvenDividing2結果:65534期間75.0043ms

maxEvenConjunctionの結果:65534期間109.0063ms

maxEvenConjunction2の結果:65534期間79.0045ms



最大しきい値:131072

maxEvenDividingの結果:131070期間108.0061ms

maxEvenDividing2の結果:131070期間76.0044ms

maxEvenConjunctionの結果:131070期間110.0063ms

maxEvenConjunction2の結果:131070期間80.0046ms



最大しきい値:262144

maxEvenDividing結果:262142期間110.0063ms

maxEvenDividing2結果:262142期間76.0044ms

maxEvenConjunctionの結果:262142期間107.0061ms

maxEvenConjunction2の結果:262142の継続時間78.0044ms



最大しきい値:524288

maxEvenDividingの結果:524286期間109.0062ms

maxEvenDividing2の結果:524286期間78.0045ms

maxEvenConjunctionの結果:524286期間109.0062ms

maxEvenConjunction2の結果:524286期間80.0046ms



最大しきい値:1048576

maxEvenDividingの結果:1048574期間109.0063ms

maxEvenDividing2の結果:1048574期間80.0045ms

maxEvenConjunctionの結果:1048574期間114.0066ms

maxEvenConjunction2の結果:1048574期間78.0044ms



最大しきい値:2097152

maxEvenDividing結果:2097150期間111.0064ms

maxEvenDividing2結果:2097150期間79.0045ms

maxEvenConjunctionの結果:2097150期間112.0064ms

maxEvenConjunction2の結果:2097150期間77.0044ms



最大しきい値:4194304

maxEvenDividing結果:4194302期間111.0063ms

maxEvenDividing2の結果:4194302期間78.0045ms

maxEvenConjunctionの結果:4194302期間111.0063ms

maxEvenConjunction2の結果:4194302期間77.0044ms



最大しきい値:8388608

maxEvenDividingの結果:8388606期間109.0062ms

maxEvenDividing2の結果:8388606期間78.0045ms

maxEvenConjunctionの結果:8388606期間114.0065ms

maxEvenConjunction2の結果:8388606の継続時間78.0045ms



最大しきい値:16777216

maxEvenDividingの結果:16777214期間109.0062ms

maxEvenDividing2結果:16777214期間77.0044ms

maxEvenConjunctionの結果:16777214期間109.0063ms

maxEvenConjunction2の結果:16777214期間77.0044ms



最大しきい値:33554432

maxEvenDividing結果:33554430継続時間113.0065ms

maxEvenDividing2結果:33554430継続時間78.0045ms

maxEvenConjunctionの結果:33554430期間110.0063ms

maxEvenConjunction2の結果:33554430期間80.0045ms



最大しきい値:67108864

maxEvenDividing結果:67108860期間112.0064ms

maxEvenDividing2結果:67108860期間77.0044ms

maxEvenConjunctionの結果:67108860期間112.0064ms

maxEvenConjunction2の結果:67108860の継続時間80.0046ms



最大しきい値:134217728

maxEvenDividingの結果:134217726期間109.0063ms

maxEvenDividing2の結果:134217726期間78.0044ms

maxEvenConjunctionの結果:134217726期間114.0065ms

maxEvenConjunction2の結果:134217726期間81.0047ms



最大しきい値:268435456

maxEvenDividingの結果:268435446期間111.0064ms

maxEvenDividing2の結果:268435446継続時間79.0045ms

maxEvenConjunctionの結果:268435446期間114.0065ms

maxEvenConjunction2の結果:268435446継続時間79.0045ms



最大しきい値:536870912

maxEvenDividingの結果:536870910期間107.0062ms

maxEvenDividing2結果:536870910期間76.0043ms

maxEvenConjunctionの結果:536870910期間109.0062ms

maxEvenConjunction2の結果:536870910期間80.0046ms



Goコンパイラがコードを最適化せず、2番目の条件を常にチェックする理由の明確な説明。たとえ最初の条件がfalseであっても、私は見つけませんでした。 それとも私の目が「ぼやけ」て、明らかな間違いが見られないのでしょうか? または、コンパイラに特別な指示を指定する必要がありますか? 私は賢明なコメントに満足しています。



PS:はい、楽しみのために、Java 5とJava 7/8で同様のテストを実行しました。すべてが明確で、実行時間は同じです。



All Articles