Пара слов к вопросу об эффективном заполнении массивов одинаковыми значениями и о том, почему нельзя слепо доверять компиляторам.
Трэвис Даунс в своем посте рассказал, что некоторые компиляторы C++ испытывают проблемы в производительности при заполнении массивов нулями. Даниэль Лемир продолжил разговор об этой проблеме в своём блоге и провёл наглядный тест для двух подходов.
Как правило, чтобы заполнить массив некоторым значением, C++ программисты вызывают std::fill. Можно предположить, что для такой простой задачи, как заполнение массива нулями, стандартная библиотека C++ обеспечивает наилучшую производительность. Однако в случае компиляторов GNU GCC это не так.
Следующая строка кода на C ++ компилируется как цикл, который заполняет каждый отдельный байт нулями с применением обычного флага оптимизации -O2.
std::fill(p, p + n, 0);
Когда массив большой, этот подход становится менее эффективен, чем реализации функций C, например, memset.
memset(p, 0, n);
Трэвис объясняет, как исправить код С++, чтобы он работал так же быстро, как функция memset.
Что насчёт очень больших массивов? Что делать, если нужно записать нули во всём двухгигабайтном массиве? Результаты теста на 2 Гб массиве следующие:
memset - 30 Гб/c
std:fill - 1.7 Гб/c
Функция memset в проведённом тесте в 15 раз быстрее, чем std::fill. Это показывает, что при работе с большими объёмами данных, вас может ограничивать не пропускная способность, а просто неэффективная реализация алгоритма. Заполнение через std::fill в этом случае работает медленнее, чем хороший сетевой адаптер или быстрый диск.
Другой урок, который можно извлечь из этого примера, состоит в том, что просто писать код на C++ недостаточно для обеспечения хорошей производительности. Хотя существует много технических решений, направленных на то, чтобы сделать C++ быстрым, и, обычно всё прекрасно работает, нужно сохранять бдительность.