2008-10-07 5 views
27

Это действительно два вопроса, но они настолько похожи, и сохранить его простым, я решил просто свернуть их вместе:Как я могу ускорить свою программу Perl?

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

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

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

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

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

ответ

149

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

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

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

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

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

+19

Лучший. Отклик. Когда-либо. – pjf

+7

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

+0

Совершено, спасибо, Шерм. –

9

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

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

+0

О, хорошая точка. Подробнее об ошибке и тестовой программе, чтобы узнать, влияет ли это на ваш код, см. Http://perlbuzz.com/2008/08/red-hats-patch-slows-down-overloading-in-perl.html –

32

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

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

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

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

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

14

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

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

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

28

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

Неполный список вещей, чтобы думать о том, как вы пишете новый код:

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

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

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

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

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

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

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

  • Посмотрите на ваших регулярных выражений. Много открытых законченные кванторов (например .*) может привести к большому количеству возвратов. Проверьте Jeffrey Freidl-х Mastering Regular Expressions для всех окровавленные детали (и на нескольких языках). Кроме того, проверить his regex website.

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

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

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

9

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

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

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

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

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

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

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

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

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

9

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

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

6

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

1

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

Turbo Charged Test Suites

2

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

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

Как всегда, считают

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

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

+0

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

6

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

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

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

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

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

+0

Окончательное утверждение о том, что включение в отсортированный список O (log n) неточно, если только «список» означает, например. «Дерево» – DavidO

0

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

реальные 0m16.724s

Это время Go.

real 0m0.425s

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