Почему печать элементов массива в среднем медленнее, чем печать отдельных объектов в C ++? - PullRequest
1 голос
/ 23 января 2020

Я сделал тест, чтобы увидеть различия между доступом к элементам массива и отдельным объектам, напечатав их значения в CLI:

#include <iostream>
#include <chrono>
#include <iomanip>

int main()
{
    int a[10] = {1,2,3,4,5,6,7,8,9,10};

    int v1 = 1;
    int v2 = 2;
    int v3 = 3;
    int v4 = 4;
    int v5 = 5;
    int v6 = 6;
    int v7 = 7;
    int v8 = 8;
    int v9 = 9;
    int v10 = 10;

    std::cout << "Array output:" << std::endl << std::endl;

    auto t_start1 = std::chrono::high_resolution_clock::now();

    std::cout << "1. value: " << a[0] << std::endl;
    std::cout << "2. value: " << a[1] << std::endl;
    std::cout << "3. value: " << a[2] << std::endl;
    std::cout << "4. value: " << a[3] << std::endl;
    std::cout << "5. value: " << a[4] << std::endl;
    std::cout << "6. value: " << a[5] << std::endl;
    std::cout << "7. value: " << a[6] << std::endl;
    std::cout << "8. value: " << a[7] << std::endl;
    std::cout << "9. value: " << a[8] << std::endl;
    std::cout << "10. value: " << a[9] << std::endl;

    auto t_end1 = std::chrono::high_resolution_clock::now();

    std::cout << std::endl;

    std::cout << "Variable output:" << std::endl << std::endl;

    auto t_start2 = std::chrono::high_resolution_clock::now();

    std::cout << "1. value: " << v1 << std::endl;
    std::cout << "2. value: " << v2 << std::endl;
    std::cout << "3. value: " << v3 << std::endl;
    std::cout << "4. value: " << v4 << std::endl;
    std::cout << "5. value: " << v5 << std::endl;
    std::cout << "6. value: " << v6 << std::endl;
    std::cout << "7. value: " << v7 << std::endl;
    std::cout << "8. value: " << v8 << std::endl;
    std::cout << "9. value: " << v9 << std::endl;
    std::cout << "10. value: " << v10 << std::endl;


    auto t_end2 = std::chrono::high_resolution_clock::now();

    std::cout<< std::endl << "Time passed with array: "
              << std::chrono::duration<double, std::milli>(t_end1-t_start1).count()
              << " ms\n" << std::endl;
    std::cout<< std::endl << "Time passed with variables: "
              << std::chrono::duration<double, std::milli>(t_end2-t_start2).count()
              << " ms\n" << std::endl;

    return 0;
}

В первой реализации (MingW / g ++ в Windows 10, cmd.exe), печать значений внутри элементов массива в среднем на 3 миллисекунд медленнее, чем при использовании одиночных скалярных объектов:

Таблица для Windows, g ++ / MingW:

                Array Elements:            Single Objects:   

1. Run          13.9609 ms                 9.529 ms
2. Run          11.9031 ms                 8.0936 ms
3. Run          13.3706 ms                 9.5264 ms
4. Run          12.5302 ms                 8.4723 ms
5. Run          14.4679 ms                 9.9688 ms
6. Run          12.3989 ms                 8.4326 ms
7. Run          12.8719 ms                 10.1851 ms
8. Run          10.9138 ms                 7.4481 ms
9. Run          12.8971 ms                 9.4094 ms
10. Run         11.9045 ms                 7.9391 ms
11. Run          9.9192 ms                 8.4047 ms
12. Run         13.4106 ms                 10.0296 ms

Во второй реализации (g ++ под Linux Ubuntu) печать значений внутри элементов массива в среднем на 3 микросекунд медленнее, чем при использовании одиночных скалярных объектов:

Таблица для Linux Ubuntu, g ++:

                Array Elements:            Single Objects:   

1. Run          0.013 ms                   0.008 ms
2. Run          0.012 ms                   0.007 ms
3. Run          0.013 ms                   0.008 ms
4. Run          0.014 ms                   0.009 ms
5. Run          0.012 ms                   0.008 ms
6. Run          0.013 ms                   0.008 ms
7. Run          0.013 ms                   0.009 ms
8. Run          0.014 ms                   0.009 ms
9. Run          0.012 ms                   0.008 ms
10. Run         0.013 ms                   0.009 ms
11. Run         0.012 ms                   0.009 ms
12. Run         0.012 ms                   0.008 ms 

Мой вопрос:

  • Почему печать значений в элементах массива в среднем медленнее, чем печать значения в отдельных объектах на * C ++?

* Информация: я не знаю, если печать элементов массива в целом медленнее, независимо от конкретного c языка.

Ответы [ 2 ]

6 голосов
/ 23 января 2020

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


Вы измеряете время, необходимое для форматирования и вывода элементов массива, а также flu sh выходной поток для каждого элемента (с std::endl), который включает системный вызов.

Загрузка элемента из массива намного короче. Загрузка регистра ЦП из кэша L1 занимает 4 такта ЦП (менее 1 наносекунды на 5 ГГц ЦП), из памяти (пропуск памяти последнего уровня) в i9-i9900KS ~ 215 тактов ЦП, в Ryzen ~ 280 циклов ЦП.

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


Когда я ставлю al oop вокруг времени, чтобы позволить CPU увеличивает свою частоту до максимума, страницы с ошибками страниц и разогревают кэш процессора; и заменив std::endl на '\n', я получу следующие значения времени:

Time passed with array:     0.029154 ms
Time passed with variables: 0.029286 ms

Time passed with array:     0.027148 ms
Time passed with variables: 0.027587 ms

Это показывает, что между доступом к элементам массива и скалярным переменным не существует измеримой разницы во времени (но она все еще измеряет std::cout раз).

1 голос
/ 23 января 2020

В вашем тесте, запись вещей в cout занимает ПУТЬ больше времени, чем просто доступ к ним в памяти.

Что еще хуже, он, вероятно, даже не считывает значение из массива или переменных, поскольку это значение уже известно во время компиляции. Вероятно, в обоих случаях он просто использует константу.

Чтобы доказать все это, просто попробуйте сравнить со временем вывода жестко закодированных констант. И попробуйте сравнить его со временем, которое занимает вычисление и вывод суммы этих чисел.

Мы не можем быть уверены в причине, почему первый вывод медленнее. Это зависит только от того, как ОС работает с этими выходными потоками.

...