Хобрук: Ваш путь к мастерству в программировании

Порядок кода и производительность

Я хотел найти, что быстрее: структура или массив. Итак, я написал код GO, в котором я записываю 4 значения int (1,2,3 и 4) в элементы структуры, а затем в массив длины 4. Я пытался найти время, необходимое для записи.

Случай 1: сначала я записываю значения в структуру, а затем в массив. Здесь я обнаружил, что массив работает быстрее, чем структура.

package main

import (
    "fmt"
    "time"
)

type abc struct {
    a, b, c, d int
}

func main() {

    var obj abc

    t1 := time.Now()
    obj.a = 1
    obj.b = 2
    obj.c = 3
    obj.d = 4
    t2 := time.Since(t1)

    fmt.Println("Struct access time: : ", t2)

    a := make([]int, 4)
    t3 := time.Now()
    a[0] = 1
    a[1] = 2
    a[2] = 3
    a[3] = 4
    t4 := time.Since(t3)

    fmt.Println("Array access time: : ", t4)

}

Случай 2: во-вторых, я записываю значения в массив, а затем в структуру. Здесь я обнаружил, что структура работает быстрее, чем массив.

package main

import (
    "fmt"
    "time"
)

type abc struct {
    a, b, c, d int
}

func main() {

    var obj abc

    a := make([]int, 4)
    t3 := time.Now()
    a[0] = 1
    a[1] = 2
    a[2] = 3
    a[3] = 4
    t4 := time.Since(t3)

    fmt.Println("Array access time: : ", t4)

    t1 := time.Now()
    obj.a = 1
    obj.b = 2
    obj.c = 3
    obj.d = 4
    t2 := time.Since(t1)

    fmt.Println("Struct access time: : ", t2)

}

Почему производительность зависит от того, что я пишу первым? Тот, на который я пишу первым, оказывается медленнее. Почему это так?


Ответы:


1

Другой ответ объяснил разницу во времени, давайте рассмотрим структуру и срез.

Если компилятор может определить во время компиляции, что слайс достаточно велик, доступ к элементам слайса и структуры будет генерировать идентичный код. Конечно, в действительности компилятор часто не знает, насколько велик срез, и будут применяться совершенно разные оптимизации в зависимости от того, работаете ли вы со структурой или срезом, поэтому для измерения производительности вам нужно смотреть на все в целом. программу и ее поведение, а не только одну конкретную операцию.

25.01.2017

2

Запуск любого кода в первый раз может иметь некоторые (значительные) накладные расходы, например. связанный код может быть загружен, многие вещи могут быть отложены до тех пор, пока они не потребуются (например, внутренние буферы). Запуск того же самого снова может занять значительно меньше времени, разница может быть даже на несколько порядков.

Всякий раз, когда вы хотите измерить время выполнения, вы должны запускать его много раз, измерять время выполнения нескольких запусков и вычислять среднее время. Также рекомендуется исключить первые (некоторые) прогоны из расчета по вышеуказанным причинам.

В Go лучше и проще всего использовать тестовые файлы и функции тестирования. Прочтите документацию по пакету testing для получения дополнительных сведений и примеров.

Ваш случай можно сравнить следующим образом:

package main

import "testing"

type abc struct {
    a, b, c, d int
}

func BenchmarkSlice(b *testing.B) {
    a := make([]int, 4)
    for i := 0; i < b.N; i++ {
        a[0] = 1
        a[1] = 2
        a[2] = 3
        a[3] = 4
    }
}

func BenchmarkStruct(b *testing.B) {
    a := abc{}
    for i := 0; i < b.N; i++ {
        a.a = 1
        a.b = 2
        a.c = 3
        a.d = 4
    }
}

Сохраните его в файл типа something_test.go, запустите с go test -bench .. Выход:

BenchmarkSlice-4        2000000000           1.24 ns/op
BenchmarkStruct-4       2000000000           0.31 ns/op

Вы можете видеть, что использование структуры примерно в 4 раза быстрее. Вы получите похожие (очень близкие) результаты, если измените порядок функций теста.

12.01.2017
  • в вашем стендовом тесте struct быстрее, чем slice. В заключении вы написали обратное. 12.01.2017
  • @icza Я понимаю, что ты сказал. Я ожидал, что оба кода будут работать одинаково. Разве все инструкции (и массив, и структура) не будут похожи на STR ‹address› ‹Value›. Таким образом, оба должны иметь одинаковое время выполнения 12.01.2017
  • @Jsmith Версия среза также включает работу со значениями индекса и, возможно, проверку границ, а версия структуры - нет. 12.01.2017
  • Я только что прочитал сгенерированный код. Проверки границ опущены, как и должно быть, поскольку компилятор точно знает, насколько велик срез. Что на самом деле происходит, так это то, что записи в структуру полностью исключаются, как я полагаю, за счет устранения мертвых хранилищ, а записи в срез - нет. Создание глобальной структуры отключает устранение мертвых хранилищ, и оба работают одинаково. 12.01.2017
  • @Art Думаю, твой ответ правильный. Не могли бы вы добавить это как ответ? 24.01.2017
  • Новые материалы

    Освоение информационного поиска: создание интеллектуальных поисковых систем (глава 1)
    Глава 1. Поиск по ключевым словам: основы информационного поиска Справочная глава: «Оценка моделей поиска информации: подробное руководство по показателям производительности » Глава 1: «Поиск..

    Фишинг — Упаковано и зашифровано
    Будучи старшим ИТ-специалистом в небольшой фирме, я могу делать много разных вещей. Одна из этих вещей: специалист по кибербезопасности. Мне нравится это делать, потому что в настоящее время я..

    ВЫ РЕГРЕСС ЭТО?
    Чтобы понять, когда использовать регрессионный анализ, мы должны сначала понять, что именно он делает. Вот простой ответ, который появляется, когда вы используете Google: Регрессионный..

    Не зря же это называют интеллектом
    Стек — C#, Oracle Опыт — 4 года Работа — Разведывательный корпус Мне пора служить Может быть, я немного приукрашиваю себя, но там, где я живу, есть обязательная военная служба на 3..

    LeetCode Проблема 41. Первый пропущенный положительный результат
    LeetCode Проблема 41. Первый пропущенный положительный результат Учитывая несортированный массив целых чисел, найдите наименьшее пропущенное положительное целое число. Пример 1: Input:..

    Расистский и сексистский робот, обученный в Интернете
    Его ИИ основан на предвзятых данных, которые создают предрассудки. Он словно переходит из одного эпизода в другой из серии Черное зеркало , а вместо этого представляет собой хронику..

    Управление состоянием в микрофронтендах
    Стратегии бесперебойного сотрудничества Микро-фронтенды — это быстро растущая тенденция в сфере фронтенда, гарантирующая, что удовольствие не ограничивается исключительно бэкэнд-системами..