Как использовать темы в Perl? - PullRequest
2 голосов
/ 21 октября 2011

Я хочу использовать потоки в Perl для увеличения скорости моей программы ... например, я хочу использовать 20 потоков в этом коде:

use IO::Socket;
my $in_file2 = 'rang.txt';
open DAT,$in_file2;
my @ip=<DAT>;
close DAT;
chomp(@ip);
foreach my $ip(@ip)
{
    $host = IO::Socket::INET->new(
        PeerAddr => $ip,
        PeerPort => 80,
        proto    => 'tcp',
        Timeout=> 1
    ) 
    and open(OUT, ">>port.txt");
    print OUT $ip."\n";
    close(OUT);
}

В приведенном выше коде мы даем список ips и сканируем данный порт. Я хочу использовать темы в этом коде. Есть ли другой способ увеличить скорость моего кода?

Спасибо.

Ответы [ 3 ]

6 голосов
/ 21 октября 2011

Вместо использования потоков, вы можете посмотреть AnyEvent :: Socket , или Coro :: Socket , или POE , или Parallel :: ForkManager .

4 голосов
/ 21 октября 2011

Прочитайте Учебник по Perl .

3 голосов
/ 29 апреля 2015

Perl может выполнять как потоки, так и разветвления.«Потоки» официально не рекомендуется - в значительной степени потому, что они не совсем понятны и, возможно, слегка противоречивы - не легки, как потоки в некоторых языках программирования.

Если вы особенно увлекаетесь потоками, модель потоков «работника» работает намного лучше, чем порождает поток для каждой задачи.Вы можете сделать последнее на некоторых языках - в Perl это очень неэффективно.

Таким образом, вы можете сделать что-то вроде этого:

#!/usr/bin/env perl

use strict;
use warnings;

use threads;
use Thread::Queue;
use IO::Socket;

my $nthreads = 20;

my $in_file2 = 'rang.txt';

my $work_q   = Thread::Queue->new;
my $result_q = Thread::Queue->new;

sub ip_checker {
    while ( my $ip = $work_q->dequeue ) {
        chomp($ip);
        $host = IO::Socket::INET->new(
            PeerAddr => $ip,
            PeerPort => 80,
            proto    => 'tcp',
            Timeout  => 1
        );
        if ( defined $host ) {
            $result_q->enqueue($ip);
        }
    }
}

sub file_writer {
    open( my $output_fh, ">>", "port.txt" ) or die $!;
    while ( my $ip = $result_q->dequeue ) {
        print {$output_fh} "$ip\n";
    }
    close($output_fh);
}


for ( 1 .. $nthreads ) {
    push( @workers, threads->create( \&ip_checker ) );
}
my $writer = threads->create( \&file_writer );

open( my $dat, "<", $in_file2 ) or die $!;
$work_q->enqueue(<$dat>);
close($dat);
$work_q->end;

foreach my $thr (@workers) {
    $thr->join();
}

$result_q->end;
$writer->join();

При этом используется очередь для подачи набора (20) рабочих потоков со списком IP-адресов и прохождения через них,сопоставление и печать результатов через поток writer.

Но поскольку потоки на самом деле больше не рекомендуются, лучшим способом может быть использование Parallel::ForkManager, который с вашим кодом может выглядеть примерно так:

#!/usr/bin/env perl

use strict;
use warnings;

use Fcntl qw ( :flock );
use IO::Socket;

my $in_file2 = 'rang.txt';
open( my $input,  "<", $in_file2 )  or die $!;
open( my $output, ">", "port.txt" ) or die $!;

my $manager = Parallel::ForkManager->new(20);
foreach my $ip (<$input>) {
    $manager->start and next;

    chomp($ip);
    my $host = IO::Socket::INET->new(
        PeerAddr => $ip,
        PeerPort => 80,
        proto    => 'tcp',
        Timeout  => 1
    );
    if ( defined $host ) {
        flock( $output, LOCK_EX );    #exclusive or write lock
        print {$output} $ip, "\n";
        flock( $output, LOCK_UN );    #unlock
    }
    $manager->finish;
}
$manager->wait_all_children;
close($output);
close($input);

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

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

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

Вероятно, в целом лучше смотреть на разветвление - как сказано выше, в threads документах:

«Основанные на интерпретаторе потоки», предоставляемые Perl, не являются быстрыми и легкими.система многозадачности, которую можно ожидать или надеяться.Потоки реализованы таким образом, что их легко использовать неправильно.Мало кто знает, как правильно их использовать, или сможет оказать помощь.Использование потоков на основе интерпретатора в perl официально не рекомендуется.

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