Стратегии оптимизации производительности последней инстанции

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

Давайте предположим:

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

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

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

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

вопрос задан 29.05.2009
jerryjvl
14565 репутация

34 ответов


  • 407 рейтинг

    Хорошо, вы определяете проблему так, чтобы казалось, что не так много возможностей для улучшения. По моему опыту, это довольно редко. Я пытался объяснить это в докторе Статья Доббса, опубликованная в ноябре 93 года, была основана на хорошо спроектированной нетривиальной программе без очевидных потерь и прошла серию оптимизаций, пока время настенных часов не сократилось с 48 секунд до 1. 1 секунда, а размер исходного кода был уменьшен в 4 раза. Мой диагностический инструмент был . Последовательность изменений была такой:

    • Первой найденной проблемой было использование кластеров списков (теперь называемых «итераторами» и «классами контейнеров»), занимающих более половины времени. Они были заменены довольно простым кодом, сократив время до 20 секунд.

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

    • Теперь труднее найти очевидных преступников, но есть несколько более мелких, с которыми я могу что-то сделать, и время сокращается до 13 секунд.

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

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

    • Эта редизайн завершен, исходный код сокращен в 4 раза, а время сокращено до 10 секунд.

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

    • Дополнительная диагностика показывает, что он проводит время в управлении очередями. В подкладке это сокращает время до 7 секунд.

    • Теперь большая часть времени занимает диагностическая печать, которую я делал. Флеш - 4 секунды.

    • В настоящее время наибольшее время занимает звонки на malloc и free . Утилизировать объекты - 2. 6 секунд

    • Продолжая выборку, я все еще нахожу операции, которые не являются строго необходимыми - 1. 1 секунда

    Общий коэффициент ускорения: 43. 6

    Теперь нет двух одинаковых программ, но в не игрушечных программах я всегда видел прогресс, подобный этому. Сначала вы получаете легкие вещи, а затем более сложные, пока не дойдете до точки убывающей отдачи. Тогда понимание, которое вы получите, может привести к редизайну, начав новый раунд ускорений, пока вы снова не достигнете убывающей отдачи. Теперь можно задаться вопросом: быстрее ли ++i, или i++, или for(;;), или while(1): вопросы, которые я так часто вижу по SO.

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

    ДОБАВЛЕНО: jerryjvl запросил несколько примеров. Здесь первая проблема. Он состоит из небольшого количества отдельных строк кода, занимающих вдвое меньше времени:

     /* IF ALL TASKS DONE, SEND ITC_ACKOP, AND DELETE OP */
    if (ptop->current_task >= ILST_LENGTH(ptop->tasklist){
    . . .
    /* FOR EACH OPERATION REQUEST */
    for ( ptop = ILST_FIRST(oplist); ptop != NULL; ptop = ILST_NEXT(oplist, ptop)){
    . . .
    /* GET CURRENT TASK */
    ptask = ILST_NTH(ptop->tasklist, ptop->current_task)
    

    Они использовали кластер списков ILST (аналог класса списков). Они реализованы обычным способом, причем «скрытие информации» означает, что пользователям класса не нужно было заботиться о том, как они были реализованы. Когда эти строки были написаны (примерно из 800 строк кода), не было мысли о том, что это может быть «узким местом» (я ненавижу это слово). Они просто рекомендуемый способ делать вещи. Легко сказать в ретроспективе , что этого следует избегать, но по моему опыту все проблемы с производительностью такие. В общем, хорошо стараться избегать проблем с производительностью. Еще лучше найти и исправить те, которые были созданы, даже если их «следовало бы избежать» (задним числом). Я надеюсь, что это дает немного аромата.

    Вот вторая проблема, в двух отдельных строках:

     /* ADD TASK TO TASK LIST */ 
    ILST_APPEND(ptop->tasklist, ptask)
    . . .
    /* ADD TRANSACTION TO TRANSACTION QUEUE */
    ILST_APPEND(trnque, ptrn)
    

    Это строит списки, добавляя элементы к их концу. (Исправление заключалось в том, чтобы собирать элементы в массивы и создавать списки сразу. Интересно то, что эти заявления только стоят (т.е. е. были на стеке вызовов) 3/48 от первоначального времени, так что на самом деле они не были большой проблемой в начале . Тем не менее, после устранения первой проблемы они стоили 3/20 времени, и теперь стали «большей рыбой». В общем так и происходит.

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

    ДОБАВЛЕНИЕ ДОБАВЛЕНО: Исходный код, как оригинальный, так и переработанный, можно найти по адресу www. DDJ. com , за 1993 год, в файле 9311. почтовый индекс, файлы слизень. Asc и Slug. почтовый индекс

    ИЗМЕНИТЬ 2011/11/26: В настоящее время существует проект sourceforge , содержащий исходный код в Visual C ++ и подробное описание его настройки. Он проходит только первую половину сценария, описанного выше, и не следует точно такой же последовательности, но все равно получает ускорение на 2-3 порядка.

    ответ дан Mike Dunlavey, с репутацией 35117, 29.05.2009
  • 179 рейтинг

    Предложения:

    • Предварительное вычисление, а не повторное вычисление Диапазон входов. Тогда используйте простой поиск внутри алгоритма.
      Обратная сторона : если на самом деле используются лишь несколько предварительно вычисленных значений, это может ухудшить ситуацию, а поиск может занять значительную память.
    • Не используйте библиотечные методы : большинство библиотек должны быть написаны для правильной работы в широком диапазоне сценариев и выполнения нулевых проверок параметров и т. Д. Повторно внедрив метод, вы сможете избавиться от большого количества логики, которая не применяется в конкретных обстоятельствах, когда вы используете его.
      Нижние стороны : написание дополнительного кода означает большую площадь для ошибок.
    • Используйте библиотечные методы : чтобы противоречить самому себе, языковые библиотеки пишутся людьми, которые намного умнее вас или меня; Скорее всего, они сделали это лучше и быстрее. Не выполняйте это самостоятельно, если вы не можете сделать это быстрее (т.е. е. : всегда измеряй! )
    • Cheat : в некоторых случаях, хотя для вашей проблемы может существовать точный расчет, вам может не потребоваться «точное», иногда приближение может быть «достаточно хорошим» и намного быстрее в сделке. Спросите себя, действительно ли имеет значение, если ответ отсутствует на 1%? 5%? даже 10%?
      Минусы : Хорошо. , , ответ не будет точным.
    ответ дан jerryjvl, с репутацией 14565, 29.05.2009
  • 158 рейтинг

    Когда вы больше не можете улучшить производительность - посмотрите, можно ли вместо этого улучшить воспринимаемую производительность .

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

    Несколько примеров:

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

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

    ответ дан kenj0418, с репутацией 4907, 29.05.2009
  • 131 рейтинг

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

    • Кеш пропускает . Кеш данных является источником номер 1 в большинстве программ. Повысить частоту обращений к кэшу за счет реорганизации поврежденных структур данных, чтобы обеспечить лучшую локальность; упаковать структуры и числовые типы, чтобы исключить потерянные байты (и, следовательно, потерянные выборки из кэша); Предварительная выборка данных везде, где это возможно, чтобы уменьшить задержки.
    • Хит-магазины . Предположения компилятора о совмещении указателей и случаи, когда данные перемещаются между несвязанными наборами регистров через память, могут вызывать определенное патологическое поведение, которое приводит к очистке всего конвейера ЦП при операции загрузки. Найдите места, где поплавки, векторы и целые числа приводятся друг к другу и устраните их. Используйте __restrict, чтобы пообещать компилятору о псевдонимах.
    • Микрокодирование . У большинства процессоров есть некоторые операции, которые нельзя конвейеризовать, но вместо этого они выполняют крошечную подпрограмму, хранящуюся в ПЗУ. Примерами на PowerPC являются целочисленное умножение, деление и сдвиг по переменной. Проблема заключается в том, что весь конвейер останавливается во время выполнения этой операции. Постарайтесь исключить использование этих операций или, по крайней мере, разбить их на составляющие их конвейерные операции, чтобы вы могли получить преимущество суперскалярной диспетчеризации во всем, что делает остальная часть вашей программы.
    • Филиал ошибочно прогнозирует . Они тоже опустошают трубопровод. Найдите случаи, когда ЦП тратит много времени на заправку канала после ветки, и используйте подсказку о ветке, если таковая имеется, чтобы чаще делать правильный прогноз. Или, что еще лучше, замените ветки условными перемещениями, где это возможно, , особенно после операций с плавающей запятой, потому что их канал обычно глубже, и чтение флагов условий после fcmp может привести к остановке.
    • Последовательные операции с плавающей точкой . Сделайте эти SIMD.

    И еще одна вещь, которую я люблю делать:

    • Настройте компилятор на вывод списков сборок и посмотрите, что он генерирует для функций горячей точки в вашем коде. Все эти умные оптимизации, которые «хороший компилятор должен сделать для вас автоматически»? Скорее всего, ваш фактический компилятор не делает их. Я видел, как GCC испускает действительно код WTF.
    ответ дан Crashworks, с репутацией 31997, 29.05.2009
  • 76 рейтинг

    Добавьте больше оборудования в это!

    ответ дан sisve, с репутацией 16713, 29.05.2009
  • 56 рейтинг

    Больше предложений:

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

    • Переместить ввод-вывод вперед : загрузить все данные, которые вы собираетесь нужно для расчета заранее, чтобы вы не повторил I / O ожидания в ядре критического алгоритм (и, возможно, в результате повторного поиска диска, когда загрузка всех данных одним ударом может избежать поиска).

    • Задержка ввода / вывода : Не записывайте результаты до расчет закончен, сохраните их в структуре данных и затем выбросить это за один раз в конце, когда тяжелая работа готово.

    • Резьбовой ввод / вывод : Для тех, кто достаточно смел, объедините ввод / вывод аванс »или« Задержка ввода / вывода »с фактическим расчетом по перемещая загрузку в параллельную нить, так что пока вы загружаете больше данных, на данные, которые у вас уже есть, или пока вы рассчитываете следующий пакет данных вы можете одновременно выписать результаты из последней партии.

    ответ дан jerryjvl, с репутацией 14565, 10.06.2009
  • 46 рейтинг

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

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

    Никогда не используйте select *, возвращайте только те поля, которые вам действительно нужны. Это особенно верно, если есть какие-либо объединения, поскольку поля объединения будут повторяться и, таким образом, вызывать ненужную нагрузку как на сервер, так и в сеть.

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

    Указатель, указатель, указатель. И обновите эту статистику, если она применима к вашей базе данных.

    Сделайте запрос sargable . Значение означает избегать вещей, которые делают невозможным использование индексов, таких как использование подстановочного знака в первом символе предложения like или функции в соединении или в качестве левой части инструкции where.

    Используйте правильные типы данных. Математику даты в поле даты быстрее выполнить, чем пытаться преобразовать строковый тип данных в тип данных date, а затем выполнить расчет.

    Никогда не вставляйте петли любого типа в триггер!

    В большинстве баз данных есть способ проверить, как будет выполняться выполнение запроса. В Microsoft SQL Server это называется планом выполнения. Сначала проверьте их, чтобы увидеть, где находятся проблемные зоны.

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

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

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

    ответ дан HLGEM, с репутацией 78315, 29.05.2009
  • 29 рейтинг

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

    Это эффекты, которые вам нужно управлять. Иногда через микро управление вашим кодом, но иногда через тщательное рассмотрение и рефакторинг.

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

    • Избегайте задержек извлечения памяти.
    • Меньшее давление на шину памяти (пропускная способность).

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

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

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

    ответ дан Mats N, с репутацией 1091, 19.06.2009
  • 25 рейтинг
    • На каком оборудовании вы работаете? Можете ли вы использовать оптимизацию для конкретной платформы (например, векторизацию)?
    • Можете ли вы получить лучший компилятор? E. г. перейти с GCC на Intel?
    • Можете ли вы заставить свой алгоритм работать параллельно?
    • Можно ли уменьшить количество кешей за счет реорганизации данных?
    • Можете ли вы отключить подтверждения?
    • Микро-оптимизация для вашего компилятора и платформы. В стиле «в случае если / еще, сначала ставим наиболее распространенное утверждение»
    ответ дан Johan Kotlinski, с репутацией 18340, 29.05.2009
  • 15 рейтинг
    • Встроенные процедуры (исключить вызов / возврат и передачу параметров)
    • Попробуйте исключить тесты / переключатели с просмотром таблиц (если они быстрее)
    • Развернуть циклы (устройство Даффа) до точки, где они просто помещаются в кэш процессора
    • Локализуйте доступ к памяти, чтобы не перегружать кэш
    • Локализуйте связанные вычисления, если оптимизатор этого еще не делает
    • Устранить инварианты цикла, если оптимизатор еще не делает этого
    ответ дан plinth, с репутацией 39983, 29.05.2009
  • 15 рейтинг

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

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

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

    ответ дан none, с репутацией 5154, 29.05.2009
  • 15 рейтинг

    Хотя мне нравится ответ Майка Данлавей, на самом деле это действительно хороший ответ с подтверждающим примером, я думаю, что его можно выразить очень просто так:

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

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

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

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

    HPH, asoudmove.

    ответ дан asoundmove, с репутацией 972, 26.01.2011
  • 12 рейтинг

    Разделяй и властвуй

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

    ответ дан MPelletier, с репутацией 11268, 22.03.2010
  • 12 рейтинг
    • Когда дело доходит до того, что вы используете эффективные алгоритмы, возникает вопрос о том, что вам нужно больше скорости или памяти . Используйте кэширование, чтобы «заплатить» в памяти для большей скорости, или используйте вычисления, чтобы уменьшить объем памяти.
    • Если возможно (и более экономически выгодно), бросают аппаратное обеспечение в проблему - более быстрый процессор, больший объем памяти или жесткий диск могут решить проблему быстрее, чем пытаться ее кодировать.
    • Если возможно, используйте распараллеливание - запустите часть кода в нескольких потоках.
    • Используйте правильный инструмент для работы . некоторые языки программирования создают более эффективный код с использованием управляемого кода (т.е. е. Джава/. NET) ускоряет разработку, но родные языки программирования создают быстрее работающий код.
    • Микро оптимизировать . Только в тех случаях, когда это применимо, вы можете использовать оптимизированную сборку для ускорения небольших фрагментов кода, а использование SSE / векторной оптимизации в нужных местах может значительно повысить производительность.
    ответ дан Dror Helper, с репутацией 23312, 30.05.2009
  • 11 рейтинг

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

    • . , , если это память - найдите одну из книг, написанных давным-давно Кнутом, одну из серии «Искусство программирования». Скорее всего, речь идет о сортировке и поиске - если у меня не в порядке с памятью, вам придется выяснить, в чем он говорит о том, как бороться с медленным хранением данных на ленте. Мысленно преобразуйте его пару памяти / ленты в вашу пару кэш / основная память (или в пару кэш-памяти L1 / L2) соответственно. Изучите все приемы, которые он описывает, - если вы не нашли что-то, что решает вашу проблему, то наймите профессионального компьютерного ученого для проведения профессионального исследования. Если у вас случайно возникла проблема с памятью из-за FFT (при выполнении бабочек из radix-2 не хватает кэша при обращенных к битам индексах), тогда не нанимайте ученого - вместо этого вручную оптимизируйте проходы один за другим, пока вы не выиграете или не получите в тупик. Вы упомянули выжать до последних нескольких процентов правильно? Если , то мало , вы, скорее всего, выиграете.

    • . , , если это процессор - переключитесь на ассемблер. Изучите спецификацию процессора - , что снимает тики , VLIW, SIMD. Вызовы функций, скорее всего, заменяемые тикеры. Изучите цикл преобразований - конвейер, разверните. Умножения и деления могут быть заменяемыми / интерполированными со сдвигами битов (умножения на маленькие целые числа могут быть заменены сложениями). Попробуйте трюки с более короткими данными - если вам повезет, одна инструкция с 64 битами может заменить две на 32 или даже 4 на 16 или 8 на 8 бит. Попробуйте также более длинные данные - например, ваши вычисления с плавающей запятой могут выполняться медленнее, чем двойные вычисления на конкретном процессоре. Если у вас есть тригонометрические вещи, боритесь с ними с заранее рассчитанными таблицами; также имейте в виду, что синусоидальное значение может быть заменено этим значением, если потеря точности находится в допустимых пределах.

    • . , , если это сеть - подумайте о сжатии данных, которые вы передаете по ней. Замените передачу XML двоичным. Протоколы обучения. Попробуйте UDP вместо TCP, если вы можете как-то справиться с потерей данных.

    • . , , если это база данных, хорошо, зайдите на любой форум базы данных и попросите совета. Сетка данных в памяти, оптимизация плана запросов и т. Д. И т. Д.

    HTH :)

    ответ дан gnat, с репутацией 5990, 29.07.2011
  • 8 рейтинг

    Кэширование! Дешевый способ (с точки зрения программиста) сделать почти все быстрее - добавить слой абстракции кэширования в любую область перемещения данных вашей программы. Будь то ввод / вывод или просто передача / создание объектов или структур. Часто к фабричным классам и читателям / писателям легко добавлять кэши.

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

    ответ дан Killroy, с репутацией 450, 13.09.2009
  • 8 рейтинг

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

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

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

    ответ дан Steve Wortham, с репутацией 16387, 29.05.2009
  • 7 рейтинг

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

    ответ дан dschwarz, с репутацией 91, 29.05.2009
  • 7 рейтинг

    Последние несколько% сильно зависят от процессора и приложения. , , ,

    • отличаются архитектурой кеша, некоторые чипы имеют встроенную оперативную память вы можете отобразить напрямую, ARM (иногда) имеют вектор блок, SH4 это полезный матричный код операции. Есть ли GPU - может быть, шейдер - это путь. TMS320 очень чувствительны к ветвям внутри петель (поэтому отдельные петли и перенести условия наружу, если это возможно).

    Список можно продолжить. , , , Но такие вещи действительно последнее средство. , ,

    Сборка для x86 и запуск Valgrind / Cachegrind против кода для правильного профилирования производительности. Или Texas Instruments ' CCStudio имеет приятный профилировщик. Тогда вы действительно будете знать, где концентрироваться. , ,

    ответ дан Cwaig, с репутацией 136, 10.08.2009
  • 7 рейтинг

    Did you know that a CAT6 cable is capable of 10x better shielding off extrenal inteferences than a default Cat5e UTP cable?

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

    ответ дан Sam, с репутацией 5678, 29.01.2011
  • 7 рейтинг

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

    • Мера : Начните с понимания базовой емкости и топологии сети. Поговорите с соответствующими сетевиками в бизнесе и воспользуйтесь базовыми инструментами, такими как ping и traceroute, чтобы установить (как минимум) задержку сети из каждого клиентского местоположения в течение типичных периодов работы. Затем выполните точные измерения времени определенных функций конечного пользователя, которые отображают проблемные симптомы. Запишите все эти измерения, а также их местоположение, даты и время. Подумайте о том, чтобы встроить функциональность «тестирования производительности сети» для конечного пользователя в ваше клиентское приложение, что позволит вашим опытным пользователям участвовать в процессе улучшения; расширение их прав может иметь огромное психологическое воздействие, равное , когда вы имеете дело с пользователями, разочарованными в плохо работающей системе.

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

    • Кэш : найдите случаи, когда статические или редко изменяемые данные передаются многократно, и рассмотрите соответствующую стратегию кэширования. Типичные примеры включают значения «списка выбора» или другие «ссылочные объекты», которые могут быть удивительно большими в некоторых бизнес-приложениях. Во многих случаях пользователи могут согласиться с тем, что им необходимо перезапустить или обновить приложение, чтобы обновить нечасто обновляемые данные, особенно если оно может значительно сократить время отображения часто используемых элементов пользовательского интерфейса. Убедитесь, что вы понимаете реальное поведение уже развернутых элементов кэширования - многие распространенные методы кэширования (например, г. HTTP ETag) по-прежнему требует обхода по сети для обеспечения согласованности, а там, где задержка сети стоит дорого, вы можете избежать ее вообще, используя другой подход к кэшированию.

    • Распараллеливание : Найдите последовательные транзакции, которые не должны логически выполняться строго последовательно, и доработайте систему для их параллельной выдачи. Я имел дело с одним случаем, когда сквозной запрос имел внутреннюю сетевую задержку ~ 2 с, что не было проблемой для одной транзакции, но когда потребовалось 6 последовательных циклов 2 с, прежде чем пользователь восстановил контроль над клиентским приложением Это стало огромным источником разочарования. Обнаружение того, что эти транзакции на самом деле были независимыми, позволило им выполняться параллельно, уменьшая задержку для конечного пользователя до очень близкой к стоимости одного туда-обратно.

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

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

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

    На описанных выше этапах я сосредотачиваюсь на процессе оптимизации, связанной с приложением, но, конечно, вы должны убедиться, что базовая сеть настроена наиболее эффективным образом для поддержки вашего приложения. Привлеките сетевых специалистов к работе и определите, могут ли они применить улучшения емкости, QoS, сжатие сети или другие методы для решения проблемы. Обычно они не понимают потребностей вашего приложения, поэтому важно, чтобы вы (после этапа анализа) имели возможность обсудить его с ними, а также обосновать любые расходы, которые вы собираетесь просить их понести. , Я сталкивался со случаями, когда ошибочная конфигурация сети приводила к тому, что данные приложений передавались по медленной спутниковой линии связи, а не по наземной линии связи, просто потому, что она использовала порт TCP, который не был «хорошо известен» специалистам по сетям; Очевидно, что устранение такой проблемы может оказать существенное влияние на производительность, при этом не требуется никакого программного кода или изменений конфигурации.

    ответ дан Pat, с репутацией 359, 17.04.2012
  • 6 рейтинг

    Не так глубоко и сложно, как предыдущие ответы, но здесь идет: (это более начальный / средний уровень)

    • очевидно: сухой
    • выполнить циклы задом наперед, так что вы всегда сравниваете с 0, а не с переменной
    • использовать побитовые операторы всякий раз, когда вы можете
    • разбить повторяющийся код на модули / функции
    • объекты кэша
    • локальные переменные имеют небольшое преимущество в производительности
    • максимально ограничить манипулирование строкой
    ответ дан Aaron, с репутацией 1397, 30.08.2012
  • 5 рейтинг

    Невозможно сказать. Это зависит от того, как выглядит код. Если мы можем предположить, что код уже существует, то мы можем просто посмотреть на него и выяснить, как его оптимизировать.

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

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

    Что ж, и «Показать код в SO и попросить совета по оптимизации для этого конкретного куска кода».

    ответ дан jalf, с репутацией 203342, 29.05.2009
  • 5 рейтинг

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

    Узнайте, на что тратится время Узнайте, на что именно уходит время. Это файл IO? Это процессорное время? Это сеть? Это база данных? Оптимизировать для IO бесполезно, если это не узкое место.

    Знайте свою среду Знание того, где оптимизировать, обычно зависит от среды разработки. Например, в VB6 передача по ссылке медленнее, чем передача по значению, но в C и C ++ по ссылке значительно быстрее. В C разумно попробовать что-то и сделать что-то другое, если код возврата указывает на сбой, в то время как в Dot Net перехват исключений происходит намного медленнее, чем проверка допустимого условия перед попыткой.

    Индексы Построить индексы для часто запрашиваемых полей базы данных. Вы почти всегда можете обменять пространство на скорость.

    Избегайте поиска Внутри цикла для оптимизации, я избегаю каких-либо поисков. Найти смещение и / или индекс вне цикла и повторно использовать данные внутри.

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

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

    Spawn Threads для проектов с пользовательским интерфейсом, порождая новый поток для предварительной обработки более медленных задач, приложение чувствует себя более отзывчивым, хотя и не так.

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

    ответ дан Andrew Neely, с репутацией 708, 20.07.2011
  • 5 рейтинг

    Если лучше аппаратное обеспечение, то определенно пойти на это. В противном случае

    • Проверьте, используете ли вы лучшие варианты компилятора и компоновщика.
    • Если подпрограмма «горячая точка» в другой библиотеке отличается от частой звонящей, рассмотрите возможность ее перемещения или клонирования в модуль звонящих. Устраняет некоторые накладные расходы на вызовы и может улучшить попадания в кэш (см., Как AIX статически связывает strcpy () в отдельно связанные общие объекты). Это, конечно, может также уменьшить попадания в кеш, поэтому есть одна мера.
    • Посмотрите, есть ли возможность использования специализированной версии процедуры горячей точки. Недостатком является поддержка более чем одной версии.
    • Посмотри на ассемблере. Если вы думаете, что это может быть лучше, подумайте, почему компилятор не понял этого, и как вы могли бы помочь компилятору.
    • Подумайте: действительно ли вы используете лучший алгоритм? Это лучший алгоритм для вашего размера ввода?
    ответ дан mealnor, с репутацией 50, 29.05.2009
  • 5 рейтинг

    Google способ является одним из вариантов "кэшировать его. , По возможности не трогайте диск "

    ответ дан asyncwait, с репутацией 2165, 9.10.2009
  • 4 рейтинг

    Добавление этого ответа, так как я не видел его во всех остальных.

    Минимизировать неявное преобразование между типами и знаком:

    Это относится, по крайней мере, к C / C ++. Даже если вы уже думаете, что вы свободны от преобразований - иногда полезно проверить добавление предупреждений компилятора вокруг функций, которые требуют производительности, особенно для отслеживания преобразований внутри циклов.

    GCC spesific: Вы можете проверить это, добавив несколько подробных прагм вокруг вашего кода,

    #ifdef __GNUC__
    #  pragma GCC diagnostic push
    #  pragma GCC diagnostic error "-Wsign-conversion"
    #  pragma GCC diagnostic error "-Wdouble-promotion"
    #  pragma GCC diagnostic error "-Wsign-compare"
    #  pragma GCC diagnostic error "-Wconversion"
    #endif
    
    /* your code */
    
    #ifdef __GNUC__
    #  pragma GCC diagnostic pop
    #endif
    

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

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

    ответ дан ideasman42, с репутацией 11457, 5.10.2013
  • 4 рейтинг

    Уменьшить переменные размеры (во встроенных системах)

    Если размер переменной превышает размер слова в конкретной архитектуре, это может оказать существенное влияние как на размер кода, так и на скорость. Например, если у вас 16-битная система и вы очень часто используете переменную long int, а потом понимаете, что она никогда не выйдет за пределы диапазона (-32. 768 , , 32. 767) рассмотреть вопрос об уменьшении до short int.

    По моему личному опыту, если программа готова или почти готова, но мы понимаем, что она занимает около 110% или 120% памяти программного обеспечения целевого оборудования, быстрая нормализация переменных обычно решает проблему чаще, чем нет.

    К этому времени оптимизация алгоритмов или частей самого кода может быть бесполезно бесполезной:

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

    Многие люди делают ошибку, имея переменные, которые точно хранят числовое значение единицы, для которой они используют переменную: например, их переменная time хранит точное количество миллисекунд, даже если релевантны только временные шаги, скажем, 50 мс. Возможно, если бы ваша переменная представляла 50 мс для каждого приращения, равного одному, вы могли бы вписаться в переменную, которая меньше или равна размеру слова. Например, в 8-битной системе даже простое добавление двух 32-битных переменных генерирует значительный объем кода, особенно если у вас мало регистров, в то время как 8-битные дополнения являются небольшими и быстрыми.

    ответ дан vsz, с репутацией 2564, 25.06.2011
  • 4 рейтинг

    передать по ссылке вместо значения

    ответ дан l--''''''---------'''''''''''', с репутацией 8468, 6.03.2011
  • 4 рейтинг

    Твик ОС и фреймворк.

    Это может показаться излишним, но подумайте об этом так: операционные системы и платформы созданы для многих целей. Ваше приложение делает только очень конкретные вещи. Если бы вы могли заставить ОС делать именно то, что нужно вашему приложению, и чтобы ваше приложение понимало, как работает структура (php ,. net, java) работает, вы могли бы намного лучше использовать свое оборудование.

    Facebook, например, изменил некоторые вещи уровня ядра в Linux, изменил работу memcached (например, они написали прокси memcached и использовали udp вместо tcp ).

    Другой пример этого - Window2008. Win2K8 имеет версию, в которой вы можете установить только базовую ОС, необходимую для запуска приложений X (например, г. Веб-приложения, серверные приложения). Это снижает значительную часть накладных расходов, которые ОС несет на выполнение процессов, и повышает производительность.

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

    ответ дан Nir Levy, с репутацией 3458, 13.09.2009
  • 4 рейтинг

    Иногда может помочь изменение макета ваших данных. В C вы можете переключаться с массива или структур на структуру массивов или наоборот.

    ответ дан Nosredna, с репутацией 57359, 29.05.2009
  • 3 рейтинг

    Если у вас много высокопараллельных математических вычислений с плавающей запятой, особенно с одинарной точностью, попробуйте разгрузить его на графический процессор (если он есть) с помощью OpenCL или (для чипов NVidia) CUDA. Графические процессоры обладают огромной вычислительной мощностью с плавающей запятой в своих шейдерах, которая намного выше, чем у процессоров.

    ответ дан Demi, с репутацией 1788, 11.06.2013
  • 3 рейтинг

    Такое общее утверждение невозможно, это зависит от проблемной области. Некоторые возможности:

    Поскольку вы не указали, что ваша заявка рассчитана на 100%:

    • Поиск вызовов, которые блокируют (база данных, сетевой жесткий диск, обновление дисплея), и изолируют их и / или помещают в поток.

    Если вы используете базу данных, и это Microsoft SQL Server:

    • исследовать директивы nolock и rowlock. (Есть темы на этом форуме. )

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

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

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

    В противном случае, определите ваши самые тесные петли и опубликуйте их здесь, в псевдо или нет, с некоторыми из структур данных.

    ответ дан Marco van de Voort, с репутацией 21802, 30.05.2009
  • 3 рейтинг

    На языке с шаблонами (C ++ / D) вы можете попробовать распространять постоянные значения через аргументы шаблона. Вы даже можете сделать это для небольших наборов не совсем постоянных значений с помощью переключателя.

    Foo(i, j); // i always in 0-4.
    

    становится

    switch(i)
    {
        case 0: Foo<0>(j); break;
        case 1: Foo<1>(j); break;
        case 2: Foo<2>(j); break;
        case 3: Foo<3>(j); break;
        case 4: Foo<4>(j); break;
    }
    

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

    ответ дан BCS, с репутацией 31683, 17.06.2009