Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > Проблема с потоками в Perl


Автор: Qwadrat 23.7.2009, 04:52
Есть небольшой скрипт, задача которого прочитать из файла список хостов и пропинговать каждый хост в отдельном потоке.
Код

#!/usr/bin/perl -w

use Net::Ping;
use strict;
use threads;

open (my $fh, '<', 'hosts.txt');

while (my $line = <$fh> ) {
    my @list = split(';', $line);
    threads->new(\&do_ping, $list[0],$list[1],$list[2]);
}

foreach my $thread (threads->list) {
    if ($thread->tid && !threads::equal($thread, threads->self)) {
        $thread->join;
    }
}

sub do_ping
{
    my ($host,$ip,$loops) = @_;
    my $p = Net::Ping->new("icmp");
    my $fails = 0;
    for (my $i=0; $i < $loops; $i++) {
        if ($p->ping($ip,2)) { }
        else { $fails++; }
    }

    if ($fails == $loops) {
        print "$host is unreachable. Fail count: $fails\n";
    }
    else {
        print "$host is responding. Fail count: $fails\n";
    }
    $p->close();
}
close $fh;

Каждый поток создает объект $p и выполняет $p->ping. Вроде как для каждого потока должен создаваться отдельный объект $p, но на деле $p->ping возвращает одинаковое значение для всех потоков, даже для тех, которые не должны пинговаться.
Как сказать Перлу создавать уникальный объект, не пересекающийся с другими потоками?

Автор: gcc 23.7.2009, 06:52
smokeping smile
многопоточная штука для пингования

Автор: sir_nuf_nuf 23.7.2009, 10:25
Цитата(Qwadrat @  23.7.2009,  04:52 Найти цитируемый пост)
Как сказать Перлу создавать уникальный объект, не пересекающийся с другими потоками? 

По идее - это поведение "по умолчанию", обычно наоборот нужно говорить, чтобы расшарить данные между потоками.

Еще раз New::Ping->new или $p->ping возвращает одно и то же ?
Может все хосты просто пингуются на ок ?
Как вы определили что одно и то же ?

Автор: Qwadrat 23.7.2009, 11:16
В списке хостов забиты заведомо неправильный ip, которые не должны пинговаться
Но в этом куске кода результат выполнения всегда истина, т.е. $fails никогда не увеличивается.
Код

        if ($p->ping($ip,2)) { }
        else { $fails++; }

А почему так происходит не могу понять.

Автор: sir_nuf_nuf 23.7.2009, 11:58
Блин, у меня перл без потоков собран =(

Это именно в много поточном режиме происходит ? 
попробуйте
а) запустить без потоков, последователный пинг
б) оставить один дохлый хост - запустить один поток.

Как я понял Net::Ping перловый модуль.. посему должен работать с потоками автоматически. Некоторые XS модули не thread-safe, т.е. не работают в многопоточном режиме.

Автор: Qwadrat 23.7.2009, 12:15
Да, именно в многопоточном.
Без потоков все работает как надо, просто при количестве хостов более 30 скорость работы скрипта уже не приемлема, поэтому хочется, чтобы каждый хост пинговался в отдельном потоке.
Если запустить один тред с нерабочим хостом, скрипт тоже отрабатывает как надо, говорит что хост недоступен.

Быть может действительно проблема именно в Net::Ping и стоит поискать альтернативу...

Автор: sir_nuf_nuf 23.7.2009, 12:57
Qwadrat, Да. тогда вполне вероятно, что Net::Ping либо сам не thread-safe, либо используюет такой модуль.

Только советую искать альтернативу не Net::Ping'у а потокам. Потоки в перле - не совсем надежная вещь.  
Как вариант:
1) использовать процессы вместо потоков и IPC
2) использовать асинхронную работу с сетью. Для этого дела есть пара надежных фреймворков:
POE и EV. Смотрите CPAN. Сами - по себе они универсальные,  для любых асинхронных операций, но для них есть плагин, позволяющие пинговать сервер асинхронно. Например POE::Component::Client::Ping 


В случае 2) вы работает в однопоточном режиме.

Автор: Qwadrat 23.7.2009, 13:48
Нашел модуль Net::PingICMP, работающий под Windows. С полностью аналогичным синтаксисом все работает в многопоточном режиме, так что проблема точно в Net::Ping.

Большое спасибо за советы.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)