#arrays #multithreading #perl
#массивы #многопоточность #perl
Вопрос:
Я просто изучаю Perl как четвертый язык.
Я хотел бы использовать Parallel::ForkManager
для ускорения foreach
цикла использование массива, элементы которого взяты из текстового файла.
По сути, я тестирую .txt-файл URL-адресов и хочу сделать так, чтобы он тестировал несколько элементов массива одновременно, а не по одному (в данном случае пять одновременно) и не отправлял спам по одному и тому же URL-адресу, непреднамеренно дозируя его.
Сработает ли что-то подобное?
$limit = new Parallel::ForkManager(5);
foreach (@lines) {
$limit->start and next;
$lines = $_;
... do processing here ...
$limit->finish;
}
или это было бы эквивалентно запуску этого цикла 5 раз, создавая небольшой многопоточный DoS-скрипт?
Комментарии:
1. Не будет ли $lines = $ _ испортить ваш цикл? Попробуйте «print $lines n» и посмотрите, что будет напечатано.
2. не уверен, что вы подразумеваете под «эквивалентом запуска этого цикла 5 раз»; он будет запускать до 5 дочерних процессов одновременно, да.
3. Я действительно использовал этот метод раньше, но без разветвления. Просто потому, что я хочу выполнить проверку содержимого $lines (удаление символов и т. Д.), И, Похоже, все работает нормально, оно перезаписывается на каждой итерации. Я не был уверен, что это произойдет при преобразовании в многопоточность, это больше то, что я здесь получаю.
4. Но будет ли каждый из них делать одно и то же, Т.Е. Цикл занимает в 5 раз больше времени, или он будет запускать их таким образом, чтобы цикл был в 5 раз быстрее (к чему я стремлюсь)
5. в зависимости от того, что вы делаете, это будет в 5 раз быстрее. но вы продолжаете говорить о многопоточности; это не многопоточность (если вы не в Windows, где fork эмулируется потоками?)
Ответ №1:
Это не слишком ясно из документации, но
-
Вызов
start
будет блокироваться в родительском процессе до тех пор, пока не будет запущено меньше дочерних элементов, чем указанный предел. Затем он вернет (ненулевой) дочерний PID в родительском и нулевой в дочернем -
Дочерний процесс может видеть все данные в родительском процессе, как это было при
start
вызове. Данные предположительно копируются при записи, поскольку дочерний элемент может изменять их, но изменения не отражаются в рабочей области любого другого процесса -
$pm->start and next
Идиома может показаться немного непонятной. По сути, он пропускает остальную часть цикла, еслиstart
метод возвращает истинное значение. Я предпочитаю что-то вродеmy $pid = $fm->start; next if $pid;
илиif
конструкцию в приведенном ниже коде. Оба делают одно и то же, но я думаю более разборчиво
Я рекомендую вам поэкспериментировать с этим более простым приложением, которое использует кэш из пяти дочерних потоков для печати чисел от нуля до девяти.
use strict;
use warnings;
use Parallel::ForkManager;
STDOUT->autoflush;
my $fm = Parallel::ForkManager->new(5);
for my $i (0 .. 9) {
my $pid = $fm->start;
if ($pid == 0) {
print "$in";
sleep 2;
$fm->finish;
}
}
Ответ №2:
Для тестирования используйте безопасный локальный процесс, такой как print или write, чтобы избежать рассылки спама по URL. Вот рабочий фрагмент из программы, которую я написал, которая использует fork manager.
my $pm=new Parallel::ForkManager(20);
foreach $add (@adds){
$pm->start and next;
#if email is invalid move on
if (!defined(Email::Valid::Loose->address($add))){
writeaddr(*BADADDR, $add); #address is bad
$pm->finish;
}
#if email is valid get domain name
$is_valid = Email::Valid::Loose->address($add);
if ($is_valid =~ m/@(.*)$/) {
$host = $1;
}
$is_valid="";
# perform dsn lookup to check domain
@mx=mx($resolver, $host);
if (@mx) {
writeaddr(*GOODADDR, $add); #address is good
}else{
writeaddr(*BADADDR, $add); #address is bad
}
$pm->finish;
}
Комментарии:
1. Хорошо, я обнаружил, что этот цикл действует по желанию, спасибо. Как мне лучше всего ответить на мой собственный вопрос, чтобы он помог всем, у кого такая же проблема?
2. Я что-то упускаю? Это выглядит так же, как код OP, за исключением некоторых нерелевантных операторов между
start
иfinish