Использование Parallel::ForkManager в цикле foreach

#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