22 января 2020

Как на C++ быстро заполнить нулями большой массив?

Пишу, перевожу и иллюстрирую IT-статьи. На proglib написал 140 материалов. Увлекаюсь Python, вебом и Data Science. Открыт к диалогу – ссылки на соцсети и мессенджеры: https://matyushkin.github.io/links/ Если понравился стиль изложения, упорядоченный список публикаций — https://github.com/matyushkin/lessons
Пара слов к вопросу об эффективном заполнении массивов одинаковыми значениями и о том, почему нельзя слепо доверять компиляторам.
Как на C++ быстро заполнить нулями большой массив?

Трэвис Даунс в недавнем посте рассказал, что некоторые компиляторы 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++ быстрым, и, обычно всё прекрасно работает, нужно сохранять бдительность.

Ссылка на более подробные результаты теста.

Комментарии

ВАКАНСИИ

Добавить вакансию
AppSec BP
по итогам собеседования
Flutter Developer
по итогам собеседования

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ