Сделайте ваш код быстрее с помощью секретного турбо-модуля Perl

  1. Требования
  2. Понимание MCE
  3. Начиная
  4. Работа с путями к файлам
  5. Изменение количества работников
  6. Изменение размера чанка
  7. Заключение
  8. Спасибо

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

Требования

Вам нужно будет установить модуль MCE. Электрический ток Результаты тестеров CPAN показать, что он работает на широком спектре платформ и версий Perl. Вы можете установить MCE через CPAN в командной строке:

Вам не нужно компилировать Perl с включенными потоками, чтобы получить преимущества параллельной обработки, поскольку MCE может реализовать параллельную обработку с использованием дочерних процессов через fork, вилы :: разделяемые , или же темы :: разделяемые , По умолчанию MCE проверяет наличие модуля потоков, в противном случае дочерние процессы создаются с помощью fork.

Понимание MCE

MCE-х документация описывает его реализацию как «модель банковской очереди». По сути, MCE использует до одного работника на ядро ​​на платформе хоста и распределяет работу между ними «порциями». Чанк - это просто набор элементов, таких как фрагмент массива или несколько строк файла. Рабочие будут обрабатывать каждый кусок параллельно. Фактическая «работа», выполняемая работником, обычно является выполнением подпрограммы Perl. Это станет яснее в примере ниже.

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

Начиная

Самый простой способ начать работу с MCE - это использовать одну из 3 базовых моделей автоматизации, которые поставляются с MCE. Базовые модели представляют собой замену элементов управления Perl, foreach, map и grep. Модели автоматически настраиваются - по умолчанию они используют максимальное количество ядер, доступных на хост-платформе, и выбирают оптимальный размер чанка на основе количества входных записей и типа источника.

Давайте посмотрим на модель grep. Код ниже является стандартным кодом Perl; он открывает файл nginx access.log и печатает количество записей в журнале, которые были получены от пользователя-робота:

использовать строгое; использовать предупреждения; используйте функцию «сказать»; использовать Nginx :: Log :: Entry; sub detect_robot {return Nginx :: Log :: Entry -> new ($ _ [0]) -> was_robot; } open (мой $ LOG, '<', '/var/logs/access.log'); мой $ count = grep {detect_robot ($ _)} <$ LOG>; скажем скаляр $ count;

Давайте изменим код выше, чтобы использовать модель MCE :: Grep. Новый код ниже:

использовать строгое; использовать предупреждения; используйте функцию «сказать»; использовать Nginx :: Log :: Entry; используйте MCE :: Grep; sub detect_robot {return Nginx :: Log :: Entry -> new ($ _ [0]) -> was_robot; } open (мой $ LOG, '<', '/var/logs/access.log'); мой $ count = mce_grep {detect_robot ($ _)} $ LOG; скажем скаляр $ count;

Основные изменения здесь:

  • Строка «use MCE :: Grep», которая импортирует модуль
  • Изменение grep на «mce_grep»
  • Удаление оператора diamond из дескриптора файла ($ LOG)

Другое отличие состоит в том, что этот код будет работать намного быстрее, чем в первом примере. Насколько быстрее зависит от платформы и количества входных записей. В ходе моего тестирования на четырехъядерном процессоре я обнаружил, что MCE :: Grep был стабильно на 100-150% быстрее, но с большим количеством ядер я ожидал, что это будет расти дальше.

Другие основные модели автоматизации MCE :: Loop а также MCE :: Карта работа во многом такая же была как у MCE :: Grep.

Работа с путями к файлам

MCE также предоставляет специальную функцию «mce_grep_f» для работы непосредственно с файлами (функция предусмотрена для всех моделей MCE, например, mce_loop_f и mce_map_f). Функция «mce_grep_f» требует аргумента filepath:

использовать строгое; использовать предупреждения; используйте функцию «сказать»; использовать Nginx :: Log :: Entry; используйте MCE :: Grep; sub detect_robot {return Nginx :: Log :: Entry -> new ($ _ [0]) -> was_robot; } my $ count = mce_grep_f {detect_robot ($ _)} '/var/logs/access.log'; скажем скаляр $ count;

Эта функция не работает в версии 1.504 MCE, но ее легко исправить - просто вставьте одну строку. Автор модуля Марио Рой связался со мной и любезно предоставил разница , Мне сказали, что эта функция будет исправлена ​​в следующей версии MCE. ( РЕДАКТИРОВАТЬ: теперь исправлено на 1.509 ).

При тестировании функции mce_grep_f с использованием приведенного выше кода в файле журнала размером 55 МБ я не заметил заметной разницы в производительности по сравнению с mce_grep, однако есть сообщения об увеличении скорости до 4 раз, поэтому обязательно рассмотрим это подробнее.

Изменение количества работников

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

  • Linux: читает / proc / stat
  • OSX / BSD: выполняет «sysctl -n hw.ncpu 2> / dev / null»
  • Windows: использует переменную среды: ENV {NUMBER_OF_PROCESSORS}

MCE также имеет платформо-зависимые методы, определенные для Solaris, HP-UX и других систем. Предполагая, что MCE будет правильно угадывать число процессоров, единственной причиной изменения поведения по умолчанию будет использование менее 100% доступных ядер. Вы можете сделать это, используя метод init ():

используйте MCE :: Grep; MCE :: Grep :: init ({max_workers => 3});

Приведенный выше код использует MCE :: Grep, но одна и та же команда init () предоставляется для всех моделей MCE.

Изменение размера чанка

Когда тип источника является массивом, MCE автоматически вычисляет размер чанка на основе количества входных записей и доступных рабочих. Вы можете переопределить это, однако в моем тестировании я обнаружил, что автоматически рассчитанный размер чанка был почти всегда оптимальным. Вот типичный набор результатов для обработки файла журнала 55 МБ:

Если тип источника - файловый дескриптор, то размер порции по умолчанию равен 2 (автор модуля Марио Рой сказал мне, что это изменится в следующей версии, 1.506). Поэтому вы можете изменить размер куска, чтобы повысить производительность. Вы можете сделать это, используя метод init ():

используйте MCE :: Grep; MCE :: Grep :: init ({chunk_size => 500});

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

Заключение

Автор MCE, Марио Рой проделал замечательную работу, предоставив простой API и фантастический документация , Очень легко начать работу с базовой моделью автоматизации, такой как MCE :: Grep, и получить мгновенные улучшения скорости. Однако в MCE есть гораздо больше, таких как процедуры инициализации и завершения работы, обратные вызовы и последовательность. Не забудьте проверить это.

Спасибо

Спасибо Джеффу Тэлхаммеру ( Stratopan ) для защиты этого модуля.

Знаете ли вы модуль, который вы хотели бы, чтобы мы покрыли? Если это так, мы хотели бы услышать от вас! Пишите нам по адресу: [email protected]


Эта статья была первоначально размещена на PerlTricks.com ,

Знаете ли вы модуль, который вы хотели бы, чтобы мы покрыли?