2014-11-13 1 views
5

В следующем коде показаны два теста. Первая создает структуру по значению в каждой итерации, а вторая использует указатель на структуру.Показатель GoLang Pointer

Почему последние в 20 раз медленнее? Я знаю о проблемах с GC с GoLang, но не должен избегать анализа этих ситуаций?

Я использую go1.4beta1, но 1.3.3 дал мне [тот же самый] другой результаты.

Любая идея?

package main 

import "testing" 

type Adder struct { 
    vals []int 
} 

func (a *Adder) add() int { 
    return a.vals[0] + a.vals[1] 
} 

func BenchmarkWithoutPointer(b *testing.B) { 
    accum := 0 
    for i := 0; i < b.N; i++ { 
     adder := Adder{[]int{accum, i}} 
     accum = adder.add() 
    } 
    _ = accum 
} 

func BenchmarkWithPointer(b *testing.B) { 
    accum := 0 
    for i := 0; i < b.N; i++ { 
     adder := &Adder{[]int{accum, i}} 
     accum = adder.add() 
    } 
    _ = accum 
} 

Тест go1.4.1:

$ go test -bench=.                                

testing: warning: no tests to run 
PASS 
BenchmarkWithoutPointer 1000000000   2.92 ns/op 
BenchmarkWithPointer 30000000   57.8 ns/op 
ok  github.com/XXXXXXXXXX/bench/perf 5.010s 

Тест go1.3.3:

testing: warning: no tests to run 
PASS 
BenchmarkWithoutPointer 500000000   7.89 ns/op 
BenchmarkWithPointer 50000000   37.5 ns/op 
ok  

РЕДАКТИРОВАТЬ:

Вывод:

Как сказал Айнар-G, то [] int уходит в кучу в secon d. Прочитав немного больше о 1.4beta1, кажется, что новые возможности для записи возникают при доступе к куче, вызванном новыми планами GC. Но сырое исполнение, похоже, увеличилось. С нетерпением ждем 1.5 =).

+2

Что машинный код генерируется для двух? – delnan

+1

https://gist.github.com/chrisprobst/4c0231c24e1fc4a215cd – Kr0e

ответ

7

Запуск отсчета с -m gcflag дает возможный ответ:

./main_test.go:16: BenchmarkWithoutPointer []int literal does not escape 
(...) 
./main_test.go:25: []int literal escapes to heap 

Ваш []int во втором примере ускользает до кучи, что медленнее, чем стек. Если вы используете отдельные x и y поля для аргументов вместо кусочка

type Adder struct { 
    x, y int 
} 

func (a *Adder) add() int { 
    return a.x + a.y 
} 

бенчмарк показывает ожидаемое поведение:

BenchmarkWithoutPointer 1000000000    2.27 ns/op 
BenchmarkWithPointer 2000000000    1.98 ns/op 
+0

Понятно, я просто просмотрел машинный код. Вторая функция содержит вызов «0x00d8 00216 (bench_test.go: 25) \t CALL \t, runtime.writebarrierslice (SB)». Знаете ли вы, почему считается, что ломтик сбрасывается? По-моему, на самом деле это не «ускользает». – Kr0e

+1

@ Kr0e Имеются [вопросы] (https://code.google.com/p/go/issues/list?q=escape+analysis) с помощью анализа эвакуации. Они известны, и некоторые из них планируется установить в 1.5. До тех пор, * если ваш код очень чувствителен к производительности, * используйте контрольные отметки, '-gcflags '-m'' или попробуйте другой компилятор. –

+1

Хорошо, спасибо товарищу! В любом случае, пример был тривиальным, конечно, использование двух целых чисел имеет смысл в этом случае. Я просто хочу понять, как идут работы (в настоящее время) =). FYI: Я сделал ошибку, 1.3.3 имеет разные характеристики. Результаты не лучше, просто разные. – Kr0e

 Смежные вопросы

  • Нет связанных вопросов^_^