Leo Matyushkin 22 января 2020

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

Leo Matyushkin

Пишу, перевожу и иллюстрирую тексты на proglib. Написал 120 материалов. Увлекаюсь Python, вебом и Data Science, но интересны и другие области разработки. Открыт к диалогу – ссылки на все соцсети, проекты и мессенджеры здесь: https://matyushkin.github.io/links/ Для отправки опечаток на десктопе выделите текст и нажмите [Ctrl]+[Enter]. Если понравился стиль изложения, на GitHub упорядоченный список публикаций и курсов: 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++ быстрым, и, обычно всё прекрасно работает, нужно сохранять бдительность.

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

Публикации Библиотеки программиста по языку C++ доступны по тегу.

МЕРОПРИЯТИЯ

Комментарии

ВАКАНСИИ

Добавить вакансию
Data Scientist
Москва, от 3000 USD до 5000 USD
Оператор 1C
Краснодар, от 25000 RUB до 40000 RUB

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