В C ускоряет ли использование статических переменных в функции?

StackOverflow https://stackoverflow.com/questions/3835857

Вопрос

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

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

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

Это было полезно?

Решение

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

Кроме того, локальные переменные, вероятно, быстрее из-за местной местности кэша.

Если вы называете только вашу функцию «Тысячи» раз (не миллионы или миллиарды), то вы должны смотреть на ваш алгоритм для возможностей оптимизации после Вы запускаете профилировщик.


Re: Cache Cache (Читать дальше здесь): Часто доступные глобальные переменные, вероятно, имеют временную местность. Они также могут быть скопированы в реестр во время выполнения функций, но будут записаны обратно в память (кэш) после возврата функции (в противном случае они не будут доступны для чего-либо еще; регистры не имеют адресов).

Локальные переменные обычно имеют как временную, так и пространственную местность (они получают это в силу создания на стеке). Кроме того, они могут быть «выделены» непосредственно для регистрации и никогда не записываются в память.

Другие советы

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

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

Чтобы решить этот комментарий о меньшего количества параметров: процесс функций «Встраивания» по существу удаляет накладные расходы, связанные с вызовом функции. Скорее всего, небольшая функция будет автоматически включена компилятором, но вы можете Предложите функцию быть установленным также.

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

Я подозреваю, что вы преждевременно оптимизируете, однако, вы не должны быть заинтересованы с производительностью, пока вы не обнаружили свои настоящие узкие места.

Абсолютно нет! Единственная «производительность» разница в том, когда переменные инициализированы

    int anint = 42;
 vs
    static int anint = 42;

В первом случае целое число будет установлено на 42 каждый раз, когда функция вызывается во втором случае OT будет установлено на 42, когда программа загружена.

Однако разница настолько тривиальна, чтобы быть едва заметным. Это общее заблуждение, которое хранение должно быть выделено для «автоматических» переменных на каждом вызове. Это не так, C использует уже выделенное пространство в стеке для этих переменных.

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

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

Рассмотреть два крайности; Если у вас есть только одна или несколько локальных переменных, он / они могут быть легко сохранены в регистрах, а не выделяются местами памяти вообще. Если регистрация «давления» достаточно низкое, что может произойти, не выполняя любые инструкции вообще.

На противоположном крайности есть несколько машин (например, мэйнфреймов IBM), которые вообще не имеют стека. В этом случае, что мы обычно думаем о том, что кадры стека фактически выделяются как связанный список на куче. Как вы, наверное, догадаетесь, это может быть довольно медленный.

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

Нижняя строка: даже рекомендации для профиля вашего кода могут быть неуместны - разница может быть легко крошечной, что даже профилировщик не обнаруживает его надежно, а Только Способ быть уверенным, это изучить язык Ассамблеи, который производится (и тратить несколько лет изучения ассамблеи, достаточно хорошо, чтобы узнать что-нибудь, когда вы делать посмотри на это). Другая сторона этого состоит в том, что, когда вы имеете дело с разницей, вы даже не можете измерять надежно, шансы, что у него будет материальный эффект на скорость реального кода, настолько дистанционно, что, вероятно, не стоит проблем.

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

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

Это усугубляется при введении указателей, скажем, у вас есть следующий код:

int myFunction()
{
    SomeStruct *A, *B;
    FillOutSomeStruct(B);
    memcpy(A, B, sizeof(A);
    return A.result;
}

Компилятор знает, что указатель A и B никогда не могут перекрывать, и поэтому он может оптимизировать копию. Если A и B - глобальные, тогда они могут указывать на перекрытие или идентичную память, это означает, что компилятор должен «играть в безопасном», который медленнее. Проблема, как правило, называется «псевдонимами указателя» и может происходить во многих ситуациях, а не просто копий памяти.

http://en.wikipedia.org/wiki/pointer_alias.

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

Большинство того, которые вы упомянули, называются микрооптимизацией. Вообще, беспокоиться об этих вещах плохая идея. Отказ Это делает ваш код сложнее читать и сложнее поддерживать. Также очень вероятно представить ошибки. Вы, скорее всего, получите больше взрыва для вашего доллара, выполняющие оптимизации на более высоком уровне.

Как предложений M2TM, бегущий профилировщик, также хорошая идея. Проверить GPROF. Для того, что довольно прост в использовании.

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

C Функции C Создайте кадр стека, которая находится в том случае, если пройденные параметры поставлены, а локальные переменные помещают, а также указатель возврата к тому, где вызываемый абонент называется функцией. Здесь нет распределения управления памятью. Обычно это простое движение указателя и вот это. Доступ к данным с стека также довольно быстро. Штрафы обычно входят в игру, когда вы имеете дело с указателями.

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

Основная разница между вашими сценариями - следа памяти, не столько скорости.

Использование статических переменных может фактически сделать ваш код значительно помедленнее. Отказ Статические переменные должны существовать в области памяти «Данные». Чтобы использовать эту переменную, функция должна выполнить инструкцию нагрузки для чтения из основной памяти, или инструкция по магазинам, чтобы написать ему. Если этот регион не находится в кэше, вы теряете много циклов. Локальная переменная, которая живет на стеке, больше, безусловно, имеет адрес, который находится в кэше, и может даже быть в регистре процессора, никогда не появляясь в памяти вообще.

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

Профилирование может не увидеть разницу, разборка и зная, что искать.

Я подозреваю, что вы собираетесь получить только изменение столько, сколько несколько тактных циклов на петлю (в среднем в зависимости от компилятора и т. Д.). Иногда изменение будет драматическим улучшением или резким медленным, и что не обязательно будет потому, что домой переменные переместились в / из стека. Позвольте сказать, что вы сохраняете четырех часовых циклов на функцию Call для 10000 вызовов на процессоре 2 ГГц. Очень грубый расчет: 20 микросекунд сохранены. 20 микросекунд много или немного по сравнению с вашим текущим исполнением?

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top