std :: vector reserve () и push_back () быстрее, чем resize () и индекс массива, почему? - PullRequest
36 голосов
/ 22 сентября 2009

Я проводил быстрый тест производительности на блоке кода

void ConvertToFloat( const std::vector< short >& audioBlock, 
                     std::vector< float >& out )
{
    const float rcpShortMax = 1.0f / (float)SHRT_MAX;
    out.resize( audioBlock.size() );
    for( size_t i = 0; i < audioBlock.size(); i++ )
    {
        out[i]  = (float)audioBlock[i] * rcpShortMax;
    }
}

Я был доволен ускорением по сравнению с оригинальной очень наивной реализацией, для обработки 65536 аудиосэмплов требуется чуть более 1 мс.

Однако, просто для удовольствия, я попробовал следующее

void ConvertToFloat( const std::vector< short >& audioBlock, 
                     std::vector< float >& out )
{
    const float rcpShortMax = 1.0f / (float)SHRT_MAX;
    out.reserve( audioBlock.size() );
    for( size_t i = 0; i < audioBlock.size(); i++ )
    {
        out.push_back( (float)audioBlock[i] * rcpShortMax );
    }
}

Теперь я полностью ожидал, что это даст точно такую ​​же производительность, что и исходный код. Однако неожиданно цикл теперь занимает 900 мкс (то есть на 100 мкс быстрее, чем в другой реализации).

Может кто-нибудь объяснить, почему это даст лучшую производительность? resize() инициализирует недавно выделенный вектор, где резерв только распределяет, но не создает? Это единственное, о чем я могу думать.

PS это было проверено на одноядерном 2Ghz AMD Turion 64 ML-37.

Ответы [ 4 ]

59 голосов
/ 22 сентября 2009

Инициализирует ли изменение размера только что выделенный вектор, где резерв только распределяет, но не создает?

Да.

4 голосов
/ 26 сентября 2009

Изменение размера ()

Изменяет контейнер так, чтобы он имел ровно n элементов, вставляя элементы в конец или стирая элементы с конца, если это необходимо. Если какие-либо элементы вставлены, они являются копиями t. Если n > a.size(), это выражение эквивалентно a.insert(a.end(), n - size(), t). Если n < a.size(), это эквивалентно a.erase(a.begin() + n, a.end()).

Резерв ()

Если n меньше или равно capacity(), этот вызов не имеет никакого эффекта. В противном случае это запрос на выделение дополнительной памяти. Если запрос выполнен успешно, capacity() больше или равно n; в противном случае capacity() не изменяется. В любом случае size() не изменяется.

Память будет перераспределена автоматически, если в вектор будет вставлено более capacity() - size() элементов. Перераспределение не меняет size() и не изменяет значения любых элементов вектора. Это, однако, увеличивает capacity()

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

3 голосов
/ 22 сентября 2009

Первый код записывает в out[i], что сводится к begin() + i (т.е. добавление). Второй код использует push_back, что, вероятно, немедленно записывает в известный указатель, эквивалентный end() (т.е. без добавления). Вероятно, вы могли бы выполнить первый запуск так же быстро, как и второй, используя итераторы, а не целочисленную индексацию.

Редактировать: также, чтобы уточнить некоторые другие комментарии: вектор содержит числа с плавающей запятой, а построение числа с плавающей запятой фактически не допускается (так же, как объявление «float f;» не генерирует код, только сообщает компилятор, чтобы сэкономить место для поплавка в стеке). Поэтому я думаю, что любая разница в производительности между resize() и reserve() для вектора с плавающей точкой не связана со строительством.

1 голос
/ 22 сентября 2009
out.resize( audioBlock.size() );

Поскольку размер out (= 0) меньше, чем audioBlock.size(), дополнительные элементы создаются и добавляются в конец out. Это создает новые элементы, вызывая их конструктор по умолчанию.

Резерв только выделяет память.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...