Как я могу ускорить мою программу Perl? - PullRequest
28 голосов
/ 07 октября 2008

Это на самом деле два вопроса, но они очень похожи, и для простоты я решил, что я просто свожу их вместе:

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

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

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

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

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

Ответы [ 11 ]

154 голосов
/ 07 октября 2008

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

  1. Первое правило Клуба Оптимизации есть, вы не оптимизируете.
  2. Второе правило Клуба оптимизации - вы не оптимизируете без измерения.
  3. Если ваше приложение работает быстрее, чем базовый транспортный протокол, оптимизация завершена.
  4. Один фактор за раз.
  5. Нет маркетроидов, нет расписаний маркетроидов.
  6. Тестирование будет продолжаться столько, сколько потребуется.
  7. Если это ваша первая ночь в Клубе оптимизации, вы должны написать контрольный пример.

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

Найдите узкие места. Тогда возвращайся сюда, чтобы рассказать нам, кто они.

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

34 голосов
/ 07 октября 2008

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

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

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

Следующие Советы по Perl также могут оказаться полезными здесь:

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

31 голосов
/ 07 октября 2008

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

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

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

  • Perl должен компилировать исходный код каждый раз, и компиляция может быть медленной. Он должен найти все файлы и так далее. См., Например, «Своевременный запуск» Джин-Луи Леруа, где он ускоряет все, просто оптимизируя расположение модулей в @INC. Если ваши начальные затраты дороги и неизбежны, вы также можете посмотреть на постоянные perls, такие как pperl, mod_perl и т. Д.

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

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

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

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

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

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

  • Знайте, как компилируется ваш perl. Тебе действительно нужны потоки и DDEBUGGING? Это немного замедляет тебя. Проверьте утилиту perlbench для сравнения различных двоичных файлов perl.

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

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

14 голосов
/ 07 октября 2008

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

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

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

9 голосов
/ 08 октября 2008

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

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

9 голосов
/ 08 октября 2008

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

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

Я обнаружил, что некоторые операции выполняются особенно медленно:

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

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

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

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

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

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

9 голосов
/ 07 октября 2008

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

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

8 голосов
/ 08 октября 2008

Методы и вызовы подпрограмм не бесплатны в 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%, если вы не делаете что-то особенное.

6 голосов
/ 12 января 2009

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

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

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

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

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

2 голосов
/ 27 октября 2008

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

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

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

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

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

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