2009-10-23 2 views
8

Я попробовал 2 вещи: (псевдокод ниже)Векторная инициализация медленнее, чем массив ... почему?

int arr[10000]; 
for (int i = 0; i < 10000; i++) 
{ 
    for (int j = 0; j < 10000; j++) 
    { 
     arr[j] = j; 
    } 
} 

и

vector<int> arr(10000); 
for (int i = 0; i < 10000; i++) 
{ 
    for (int j = 0; j < 10000; j++) 
    { 
     arr[j] = j; 
    } 
} 

Я побежал как программы и засек его с помощью команды оболочки "время". Программа 1 работает через 5 секунд, программа 2 запускается через 30 секунд. Я запускал обе программы с оптимизацией компилятора, и обе программы работали примерно в одно и то же время (0,38 с). Я смущен этими результатами. Может кто-нибудь объяснить мне, почему это происходит?

Спасибо!

+2

Вы имеете в виду, что они занимали 5/30 секунд с оптимизацией * off *? – jalf

+0

Имейте в виду, что они не совсем эквивалентны. Вектор выделяет кучу по умолчанию, но массив находится в стеке. – GManNickG

+0

Hi jalf, да, это было частью моего вопроса. Я был также смущен тем, как они выполнялись в одно и то же время после оптимизации. – Aishwar

ответ

16

Для шаблона подписка выполняется с помощью оператора []. Когда оптимизация отключена, это обычно генерируется как вызов реальной функции, добавляя много накладных расходов к чему-то простенькому, как subscriptip в массив. Когда вы включаете оптимизацию, она генерируется встроенным, удаляя эти служебные данные.

+0

Эй, Джерри, Спасибо за ваш ответ. Теперь это имеет смысл. Я предполагаю, что с помощью массивов, используя [], не вызывает вызов оператора [], поскольку он является «естественным» (для отсутствия лучшего слова). Следовательно, 5/30. – Aishwar

+0

Право - для встроенного массива код подписи почти наверняка * всегда * создан встроенным. –

+0

И это подчеркивает, как накладные расходы функций могут действительно складываться. – Crashworks

8

В режиме отладки реализации std::vector обеспечивают большую проверку времени выполнения для удобства использования. Эта проверка недоступна для встроенных массивов. Например, в VC2008, если вы скомпилируете свой пример в режиме отладки, то будет range-checkingдаже в случае operator[].

5

Если ваша не оптимизированная векторная реализация выполняет проверку границ, это будет учитывать расхождение.

+0

++ Я думаю, вы правы, но я хотел, чтобы он (или ее) узнал. –

0

потому что, когда вы пишете вектор arr (10000); вы создаете объект, называете его функциями ... когда и будет медленнее, чем вы создаете int arr [10000];

0

В ваших примерах массив находится в стеке. Доступ к данным в массиве предполагает доступ к данным в стеке. Это быстро.

С другой стороны, в то время как vector находится в стеке, данные для std::vector выделяется в другом месте (по умолчанию он выделяется в куче с помощью std::allocator). Доступ к данным в vector включает в себя доступ к данным в куче. Это намного медленнее, чем доступ к данным в стеке.

Вы получаете что-то за штраф за выполнение. std::vector - это растение, а регулярный массив - нет. Кроме того, размер std::vector не обязательно должен составлять постоянную времени компиляции, а размер массива в стеке. Выделенный кучей массив (через operator new[]) не обязательно должен быть константой времени компиляции. Если вы сравните массив с кучей с std::vector, вы обнаружите, что производительность намного ближе.

int* arr = new int[10000]; 
for (int i = 0; i < 10000; i++) 
{ 
    for (int j = 0; j < 10000; j++) 
    { 
     arr[j] = j; 
    } 
} 

delete[] arr; // std::vector does this for you 
4

Это хорошие ответы, но есть быстрый способ, который вы можете узнать сами.

Вы видите разницу в производительности от 6 до 1, верно? Просто запустите медленный и нажмите кнопку «пауза». Затем посмотрите на стек вызовов. Вероятность составляет 5 из 6 (83%), что вы точно увидите, как они тратят эти 25 дополнительных секунд. Сделайте это несколько раз, чтобы получить такое же понимание, как вы хотите.

Для оптимизированного случая, сделайте то же самое с программой 1. Поскольку это в 13 раз медленнее, чем оптимизированная программа, вы увидите причину, по которой на каждой «паузе», с вероятностью 12/13 = 92%.

Это приложение this technique.

+1

Я видел, как многие мысли разработчиков взорвались, когда впервые увидели технику хорошего оле 'паузы, особенно когда они ее не покупают и тратят еще один серверный час, устанавливая полный прогон профилирования только для того, чтобы обнаружить «паузу», которая уже была прибита. – DanO

+0

@ DanO: Да. Я просто пытаюсь понять это. Нет причин, чтобы люди не знали этого. –

+0

Эй, Майк, спасибо за ответ. Я хотел бы попробовать, но я использую среду командной строки и gcc для компиляции моих программ (я новичок в этой среде). Есть ли какая-то возможность приостановить его и просмотреть трассировку стека? Спасибо :) – Aishwar