Причина разнобоя в показаниях заключается в том, что таймер в компьютере тикает с периодом, который значительно больше времени исполнения цикла. Значение delta == 0
соответствует тому случаю, когда цикл завершился между двумя тиками таймера - таймер не тикнул, операционная система не обновила показания времени, time.Now()
вернул одно и то же значение.
Значение delta == 1122300
можно объяснить двумя причинами.
- Таймер тикнул во время итерации, и время обновилось. Но величина задержки великовата.
- Во время выполнения цикла произшло переключение процессов в ОС и ваша программа была остановлена. Пока управление вернулось, таймер успел натикать.
КАК НАДО
Данные никогда не анализируются по минимальному и максимальному значению. Нужно среднее, среднее квадратичное и распределение.
// You can edit this code!
// Click here and start typing.
package main
import (
"fmt"
"math"
"os"
"sort"
"time"
"github.com/aybabtme/uniplot/histogram"
)
func main() {
fmt.Println("\n[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -")
var FlagLoopExt = true
arr_dlt := []int{}
arr_float := []float64{}
//
cnt := 1000 // задаю кол-во повторений внеш.цикла;
count := 1_000_000 // задаю кол-во итераций внутр.цикла;
//
for j := 0; j < cnt; j++ {
ns1 := time.Now().UnixNano() // текущее местное время;
i := 0
for {
i = i + 1
if i == count {
FlagLoopExt = false
}
if FlagLoopExt == false {
break
}
}
ns2 := time.Now().UnixNano() // текущее местное время;
delta := int(ns2 - ns1) // конвертировал int64 to int32
arr_dlt = append(arr_dlt, delta)
arr_float = append(arr_float, float64(delta))
FlagLoopExt = true
}
//
fmt.Println("Повторений (cnt) = ", cnt)
fmt.Println("Итераций в каждом повторении (count) = ", count)
//
sort.Ints(arr_dlt) // сортирует от малого до большего;
// чтобы потом посчитать среднее арифметическое значение):
sum := 0.0
sum2 := 0.0
for _, delta := range arr_float {
sum += delta
sum2 += delta * delta
}
avg := sum / float64(cnt)
std := math.Sqrt(sum2/float64(cnt) - avg*avg)
//
fmt.Println(" Наибольшее значение времени выполнения (delta) = ", arr_dlt[cnt-1])
fmt.Println(" Наименьшее значение времени выполнения (delta) = ", arr_dlt[0])
fmt.Println(" Среднее значение времени выполнения (delta) = ", int64(avg))
fmt.Println(" Среднеквадратичное отклонение (delta) = ", int64(std))
fmt.Println("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]\n ")
// fmt.Println(" Отсортировано: ", arr_dlt, "\n ")
hist := histogram.Hist(10, arr_float)
histogram.Fprint(os.Stdout, hist, histogram.Linear(10))
}
Я добавил вычисление среднеквадратичного отклонения и вывод гистограммы.
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Повторений (cnt) = 1000
Итераций в каждом повторении (count) = 1000000
Наибольшее значение времени выполнения (delta) = 2648300
Наименьшее значение времени выполнения (delta) = 0
Среднее значение времени выполнения (delta) = 959248
Среднеквадратичное отклонение (delta) = 405578
Что видно: время выполнения 0.9 мс +- 0.4 мс, то есть максимальное значение 2.6мс - это аномалия. Скорее всего, это результат переключения между процессами.
0-2.648e+05 10.3% █▍ 103
2.648e+05-5.297e+05 0.8% ▏ 8
5.297e+05-7.945e+05 1.8% ▎ 18
7.945e+05-1.059e+06 74.3% ██████████▏ 743
1.059e+06-1.324e+06 3.1% ▌ 31
1.324e+06-1.589e+06 4.5% ▋ 45
1.589e+06-1.854e+06 2% ▎ 20
1.854e+06-2.119e+06 2.8% ▍ 28
2.119e+06-2.383e+06 0.1% ▏ 1
2.383e+06-2.648e+06 0.3% ▏ 3
Это гистограмма. Максимум приходится на значения около 1мс. Я бы предположил, что это тоже переключения в контекст ядра, только без передачи управления другому процессу.
Бенчмарк
Специально экспериментов по времени выполнения в пакете testing
есть поддержка бенчмарков. Этот пакет умеет справляться с аномальными выбросами и переключениями контекста операционной системой.
package main
import "testing"
func BenchmarkLoop(b *testing.B) {
count := 1_000_000
FlagLoopExt := false
for j := 0; j < b.N; j++ {
i := 0
for {
i = i + 1
if i == count {
FlagLoopExt = false
}
if FlagLoopExt == false {
break
}
}
}
}
Запуск go test -benchmem -run=^$ -bench ^BenchmarkLoop$ .
goos: windows
goarch: amd64
pkg: example.org
cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
BenchmarkLoop-8 1000000000 1.020 ns/op 0 B/op 0 allocs/op
PASS
ok example.org 1.354s
Для верности можно прогнать бенчмарк 10 раз
go test -benchmem -run=^$ -bench ^BenchmarkLoop$ . -count 10
goos: windows
goarch: amd64
pkg: example.org
cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
BenchmarkLoop-8 1000000000 1.044 ns/op 0 B/op 0 allocs/op
BenchmarkLoop-8 1000000000 1.045 ns/op 0 B/op 0 allocs/op
BenchmarkLoop-8 1000000000 1.028 ns/op 0 B/op 0 allocs/op
BenchmarkLoop-8 1000000000 1.040 ns/op 0 B/op 0 allocs/op
BenchmarkLoop-8 1000000000 1.031 ns/op 0 B/op 0 allocs/op
BenchmarkLoop-8 1000000000 1.035 ns/op 0 B/op 0 allocs/op
BenchmarkLoop-8 939725974 1.090 ns/op 0 B/op 0 allocs/op
BenchmarkLoop-8 971966854 1.031 ns/op 0 B/op 0 allocs/op
BenchmarkLoop-8 1000000000 1.034 ns/op 0 B/op 0 allocs/op
BenchmarkLoop-8 1000000000 1.037 ns/op 0 B/op 0 allocs/op
PASS
ok example.org 13.554s
Видно, что ваш цикл достаточно стабильно завершается за 1.03 наносекунды на моей машине.