ostream_iterator против каждой эффективности цикла - PullRequest
0 голосов
/ 08 мая 2018

Я видел этих пользователей сообщение вчера . И я подумал, что это крутой способ вывести вектор. Поэтому я напечатал пример и спросил себя, как это соотносится с циклом for each?

template <typename T>
void printVectorO(std::vector<T> &v)
{
    std::cout << "Ostream_iterator contents: " << std::endl;
    auto start = std::chrono::high_resolution_clock::now();
    std::ostream_iterator<T> ost(std::cout, " ");
    std::copy(begin(v), end(v), ost);
    std::cout << std::endl;

    auto end = std::chrono::high_resolution_clock::now();
    auto time = end - start;
    auto nano = std::chrono::duration_cast<std::chrono::nanoseconds>(time);
    std::cout << "Ostream_iterator computation took: " << nano.count() << " nano seconds"<< std::endl;
    std::cout << std::endl;
}

template <typename T>
void printVectorC(std::vector<T> &v)
{
    std::cout << "For Each Loop contents: " << std::endl;
    auto start = std::chrono::high_resolution_clock::now();
    for (auto && e : v) std::cout << e << " ";
    std::cout << std::endl;

    auto end = std::chrono::high_resolution_clock::now();
    auto time = end - start;
    auto nano = std::chrono::duration_cast<std::chrono::nanoseconds>(time);
    std::cout << "For Each Loop took: " << nano.count() << " nano seconds" << std::endl;
    std::cout << std::endl;
}

Я использовал 3 вектора, чтобы проверить это:

std::vector<double> doubles = { 3.15, 2.17, 2.555, 2.014 };
std::vector<std::string> strings = { "Hi", "how", "are", "you" };
std::vector<int> ints = { 3, 2 , 2 , 2 };

И я получаю различные результаты. Цикл for each всегда превосходит ostream_iterator, когда я вывожу двойные значения (например, 41856 против 11207 и 55198 против 10308 наносекунд). Иногда строка ostream_iterator выбивает петлю for each, а петля for each и ostream_iterator почти остаются шеей и шеей с целыми числами.

Почему это? Что происходит за кулисами ostream_iterator? Когда бы я использовал ostream_iterator через for each цикл, когда дело доходит до эффективности и скорости?

1 Ответ

0 голосов
/ 21 июля 2018

Остерегайтесь микротестов.

У меня есть несколько общих комментариев относительно этого кода:

  1. Передавать переменные только для чтения как константную ссылку, а не как обычную ссылку. Это не влияет на производительность, хотя
  2. Не используйте std :: endl, так как он вызывает flush (), что в конечном итоге отнимает большую часть времени выполнения в таком микро-тесте. Например, для печати дубликатов потребовалось 37010 нс с помощью std :: endl и всего 4456 нс с '\ n'
  3. Одно измерение неточно. Чтобы сгладить любой шум измерения, вы должны запустить его много раз в цикле. Это все еще несовершенно, поскольку лучше всего выполнять тесты взаимозаменяемо (чтобы случайные события, которые могут замедлить код, влияли на обе реализации одинаково)
  4. Лучше перенаправить его в файл, в противном случае скорость терминала будет доминировать в результатах.

Вот исправленный тест:

constexpr unsigned ITERATIONS = 1000000;
template <typename T>
void printVectorO(const std::vector<T> &v)
{
    std::cout << "Ostream_iterator contents\n";
    auto start = std::chrono::high_resolution_clock::now();
    for (unsigned i=0 ; i < ITERATIONS; ++i) {
        std::ostream_iterator<T> ost(std::cout, " ");
        std::copy(begin(v), end(v), ost);
        std::cout << '\n';
    }

    auto end = std::chrono::high_resolution_clock::now();
    auto time = end - start;
    auto nano = std::chrono::duration_cast<std::chrono::nanoseconds>(time);
    std::cout << "Ostream_iterator computation took: "
              << nano.count() / ITERATIONS << " nano seconds\n\n";
}

template <typename T>
void printVectorC(const std::vector<T> &v)
{
    std::cout << "For Each Loop contents\n";
    auto start = std::chrono::high_resolution_clock::now();
    for (unsigned i=0 ; i < ITERATIONS ; ++i) {
        for (auto && e : v) std::cout << e << " ";
        std::cout << '\n';
    }

    auto end = std::chrono::high_resolution_clock::now();
    auto time = end - start;
    auto nano = std::chrono::duration_cast<std::chrono::nanoseconds>(time);
    std::cout << "For Each Loop took: "
              << nano.count() / ITERATIONS << " nano seconds\n\n";
}

И вызывать его с помощью:

template <class Container>
void test(const Container & ctr)
{
    printVectorC2(ctr);
    printVectorO2(ctr);
}


int main()
{
    std::vector<double> doubles = { 3.15, 2.17, 2.555, 2.014 };
    test(doubles);
    std::vector<std::string> strings = { "Hi", "how", "are", "you" };
    test(strings);
    std::vector<int> ints = { 3, 2 , 2 , 2 };
    test(ints);
}

А теперь, после поиска нано, имеем:

For Each Loop took: 2045 nano seconds
Ostream_iterator computation took: 2033 nano seconds
For Each Loop took: 487 nano seconds
Ostream_iterator computation took: 485 nano seconds
For Each Loop took: 503 nano seconds
Ostream_iterator computation took: 499 nano seconds

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

...