Подтвердить что ты не робот

Как я могу ускорить свою программу Perl?

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

  • Во-первых: Учитывая установленный проект Perl, каковы некоторые достойные способы ускорить его за рамки простой оптимизации в коде?

  • Во-вторых: При написании программы с нуля в Perl, какие хорошие способы значительно повысить производительность?

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

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

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

4b9b3361

Ответ 1

Пожалуйста, запомните правила Клуба Оптимизации:

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

Итак, если у вас есть рабочий код, запустите свою программу под Devel::NYTProf.

Найдите узкие места. Затем вернитесь, чтобы рассказать нам, что это такое.

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

Ответ 2

Энди уже упомянул Devel::NYTProf. Это потрясающе. Действительно, действительно потрясающе. Используйте его.

Если по какой-то причине вы не можете использовать Devel::NYTProf, тогда вы можете вернуться к старому Devel::DProf, который стандартизируйте Perl в течение длительного времени. Если у вас есть истинные функции (в математическом смысле), которые занимают много времени для вычисления (например, числа Фибоначчи), вы можете найти Memoize обеспечивает некоторое улучшение скорости.

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

Ниже приведено Perl Tips.

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

Ответ 3

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

Неполный список вещей, о которых нужно думать при написании нового кода:

  • Профиль с чем-то вроде Devel::NYTProf, чтобы увидеть, где вы тратите большую часть своего времени в коде. Иногда это удивительно и легко исправить. Освоение Perl имеет много советов по этому поводу.

  • Perl должен скомпилировать источник каждый раз, и компиляция может быть медленной. Он должен найти все файлы и так далее. См., Например, "Своевременное начало" от Jean-Louis Leroy, где он ускоряет все, просто оптимизируя расположение модулей в @INC. Если ваши затраты на запуск являются дорогостоящими и неизбежными, вы также можете посмотреть на постоянные perls, такие как pperl, mod_perl и т.д.

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

  • Вызов методов может быть дорогостоящим. Например, в наборе тестов Perl:: Critic его вызовы isa замедляют работу. Это не то, чего вы действительно можете избежать во всех случаях, но это то, что нужно помнить. У кого-то была отличная цитата, в которой говорилось что-то вроде "Никто не упускает сомнений в 2 раза, а когда десять человек делают это плохо".:) Perl v5.22 имеет некоторые улучшения производительности для этого.

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

  • Модули, такие как Apache::DBI, могут повторно использовать дескрипторы базы данных для вас, чтобы избежать дорогостоящего открытия соединений с базой данных. Это действительно простой код, поэтому просмотр внутри может показать вам, как это сделать, даже если вы не используете Apache.

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

  • Посмотрите на свои регулярные выражения. Многие кванторы с открытым концом (например, .*) могут привести к большому оттоку. Проверьте Освоение регулярных выражений для всех деталей gory (и на нескольких языках). Также проверьте его веб-сайт регулярного выражения.

  • Узнайте, как скомпилирован ваш perl. Вам действительно нужна резьба и DDEBUGGING? Те замедляют вас. Ознакомьтесь с утилитой perlbench, чтобы сравнить разные библии Perl.

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

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

Ответ 4

Не переписывая большие куски, вы можете использовать Inline:: C для преобразования любой одной медленной подпрограммы в C. Или напрямую использовать XS. Также возможно постепенное преобразование подмножеств с XS. PPI/PPI:: XS делает это, например.

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

Что касается psyco и pyrex: Нет, для Perl нет эквивалента.

Ответ 5

Это только половина относится к вашему вопросу, но в интересах документации я отправлю его здесь.

Недавний CentOS/Perl bugfix увеличил скорость нашего приложения более чем в два раза. Это необходимо для тех, кто работает с CentOS Perl и использует функции благословения/перегрузки.

Ответ 6

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

Если время тратится на то, что происходит, кроме использования ЦП, вам нужно уменьшить их - CPU легко масштабируется, другие - нет.

Несколько операций особенно медленны, я нашел:

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

    use Data::Dumper; 
    $debugstr = Dumper(\%bighash); 
    if ($debugflag_mostlyoff) { log($debugstr); } 
    
  • Большинство модулей имеют альтернативы с различными характеристиками производительности - некоторые буквально сосут невероятно плохо.

  • Некоторые регулярные выражения могут быть очень медленными (много. * и т.д.) и могут быть заменены эквивалентными, которые быстрее. Регулярные выражения довольно легки для unit test и теста производительности (просто напишите программу, которая запускает ее в цикле с большим симулированным набором данных). Лучшие регулярные выражения начинаются с чего-то, что можно протестировать очень быстро, например, буквальной строки. Иногда лучше не искать то, что вы ищете в первую очередь, и "заглянуть", чтобы проверить, действительно ли это то, что вы ищете. Оптимизация регулярных выражений на самом деле - это немного черное искусство, в котором я не очень хорош.

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

Если вы переписываете что-то на C, попробуйте сделать это таким образом, чтобы минимизировать накладные расходы на вызовы и вызовы perl runtime (функции SV *, например, в основном копируют строки). Одним из способов достижения этого является создание функции C, которая делает больше и называет ее меньше раз. Копирование строк в памяти не круто.

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

Ответ 7

Эссе, которое стоит прочитать на эту тему, - это разговор Николаса Кларка Когда perl не достаточно быстро. Некоторые из пунктов слегка устарели, например, ссылка на Devel:: DProf, но имейте в виду, что она была написана в 2002 году.

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

Ответ 8

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

Однако то, что вам не нужно делать, это заменить аксессоры, такие как get_color() здесь:

package Car;
# sub new {...}

sub get_color {
   my $self = shift;
   return $self->{color};
}

package main;
#...
my $color = $car->get_color();

с прямым доступом к инкапсуляции:

my $color = $car->{color};

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

package Car;
# sub new {...}
use Class::XSAccessor
  getters => {
    get_color => 'color',
  },
  setters => {
    set_color => 'color',
  };

Это создает новые методы get- и set_color(), которые реализованы в XS и, следовательно, примерно в два раза быстрее, чем ваша ручная версия. Мутаторы (т.е. "$ Car- > color ('red')" ) также доступны, как и цепные методы.

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

Ответ 9

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

Например, здесь некоторый код, который я увидел, вставляет элемент в отсортированный список:

while(my $new_item = <>){
    push @list, $new_item;
    @list = sort @list;
    ... use sorted list
}

sort - это O (n log n). Вставка в отсортированный список - O (log n).

Исправить алгоритм.

Ответ 10

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

Я испытал это много лет назад, когда мы перенесли приложение на основе XML-разбора (технология кратковременных ошибок в то время <g> ) с (быстрого и надежного!) Windows Server на специальную, хотя и несколько устаревшую, платформу SUN с более быстрым вводом/выводом.

Как всегда, рассмотрим

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

и улучшить, где большая часть (стоимость!) эффективна для проблемы...

Ответ 11

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

Turbo Charged Test Suites

Ответ 12

Dump Perl и используйте Golang. Я изменил свою программу, чтобы использовать Go, и она ускоряет время выполнения в 34 раза. Это время выполнения Perl.

real 0m16.724s

Это время перехода.

real 0m0.425s