2010-09-23 2 views
0

Быстрее ли доступ к глобальной или объектной переменной?Разница в скорости между глобальной и объектной переменной

В C++, я имею в виду разницу между

::foo 

и

this->foo 

В x86 ассемблере, это в основном приводит к

mov eax, offset foo 

против

mov eax, dword ptr[edx+foo] 

Ожидается, что все данные в обоих случаях будут находиться в кеше.

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

+2

Как насчет тестирования и выбора времени обоих вариантов? – sharptooth

+1

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

+0

«Под лимит времени»? Какой срок это? Полмиллиарда доступа в секунду могут означать, что это важно по производительности, но полмиллиона долларов в час сделает его совершенно несущественным. – jalf

ответ

8

Вам необходимо протестировать и время для обоих.

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

Для людей, которым Global стремится быстрее, однако, что компилятор решает поставить, где и как процессор решает кэшировать вещи, в конечном итоге решит, что быстрее.

Проверьте это и раз. Я был бы ошеломлен, если бы у вас были значимые различия в нетривиальном приложении за миллионы трасс.

+0

И нижняя сторона - это потому, что. , .? Если вы не согласны с моим ответом, можете ли вы рассказать мне, почему? Я хотел бы знать, что с ним не так, мы все здесь, чтобы учиться в конце концов :) –

1

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

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

4

Пожалуйста, не оптимизируйте это для скорости.

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

Несколько миллиардов итераций на самом деле не так уж много. Процессор на моем компьютере работает при ярком 2,2 ГГц. Если он находится в кеше, разыменование будет стоить, возможно, дополнительного цикла, и поэтому 100 миллиардов циклов составляет около 30 секунд времени выполнения. Сомневаюсь, что я пропущу.

3

Рассматривали ли вы третий вариант?

void bar() 
{ 
    foo_t myFoo = ::foo; // or this->foo 
    for(;;) 
    { 
     // do something with myFoo 
    } 
    ::foo = myFoo; 
} 

В этом случае компилятор может поместить Foo в регистре, который обязательно будет даже быстрее, чем доступ к кэш-памяти.

+3

Составители не так уж плохо приписывают регистры. На самом деле, я больше не знаю компилятора, который уважает ключевое слово 'register', так как все уверены, что ему вообще не нужен намек. – MSalters

+1

Компиляторы более склонны использовать регистры для локальных переменных, чем переменные, которые должны иметь адрес, такой как глобальная переменная (которая существует в исполняемом изображении) или явно разыменованные значения (такие как 'this-> foo') – SingleNegationElimination

3

Как всегда, используйте код, упрощающий код.

Если вы используете глобальный язык, то читателю кода нужно задаться вопросом , почему и где еще находится эта переменная. Сколько потоков они обращаются? Как синхронизируются обращения из разных потоков?

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

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

Но если код стоит оптимизировать, то это также стоит измерить.

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

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

+0

+1 для «если код стоит оптимизировать, то это также стоит измерить». Обратите внимание, что некоторые («низкопроизводительные») процессоры могут видеть разницу в скорости. Что еще более важно, относительная нагрузка с небольшим смещением, вероятно, будет меньше (по коду), чем абсолютная нагрузка; Обычно я предпочитаю версию, которая занимает меньше места в I-кеше. –

Смежные вопросы