Perl многопоточночть

Discussion in 'PHP' started by zer0ska, 27 Oct 2008.

  1. zer0ska

    zer0ska Elder - Старейшина

    Joined:
    5 Dec 2007
    Messages:
    103
    Likes Received:
    9
    Reputations:
    0
    Подскажите как скрипт такого вида cделать многопоточным или дайте ссылки на нормальные мануалы по много поточности perl.

    Code:
    #!/usr/bin/perl
    use Socket;
    
    %ipr = ('192.168.0.1' => '1',
            '192.168.0.2' => '2',
            '192.168.0.3' => '3');
    
    
    $p='135';
    
    
    foreach $ip (keys %ipr){
    
            socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
    
            $iaddr = inet_aton($ip);
            $paddr = sockaddr_in($p, $iaddr);
            if(connect(SOCK, $paddr)) {
                     print $ip." [connect]\r\n";
            }
            else {
                    print $ip." [error]\r\n";
            }
    
            # send (SOCK, "", 0);
            close(SOCK);
            $i++;
    }
    
    
     
  2. Spyder

    Spyder Elder - Старейшина

    Joined:
    9 Oct 2006
    Messages:
    1,388
    Likes Received:
    1,209
    Reputations:
    475
    Code:
    #!/usr/bin/perl
    use Socket;
    use threads;
    use threads::shared;
    my @ipr : shared;
    
    $thr = 2;    # потоки 
    @ipr = ('192.168.0.1', '192.168.0.2', '192.168.0.3');
    
    
    
    $p='135';
    
    for(0..$thr)
    {
    $trl[$_] = threads->create(\&Prog, $_);
    }
    for(0..$thr)
    {
    $trl[$_]->join;
    }
    
    sub Prog {
    
    while (@ipr){
    
            $ip = shift;
            socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
    
            $iaddr = inet_aton($ip);
            $paddr = sockaddr_in($p, $iaddr);
            if(connect(SOCK, $paddr)) {
                     print $ip." [connect]\r\n";
            }
            else {
                    print $ip." [error]\r\n";
            }
    
            # send (SOCK, "", 0);
            close(SOCK);
            $i++;
    }
    }
    
    Вроде так, только я там заюзал через массив, а не через хеш
     
    #2 Spyder, 27 Oct 2008
    Last edited: 27 Oct 2008
    1 person likes this.
  3. Spyder

    Spyder Elder - Старейшина

    Joined:
    9 Oct 2006
    Messages:
    1,388
    Likes Received:
    1,209
    Reputations:
    475
    spyder@local:~> perl tt.pl
    0 [error]
    1 [error]
    Thread 1 terminated abnormally: Bad arg length for Socket::pack_sockaddr_in, length is 0, should be 4 at /usr/lib/perl5/5.10.0/i586-linux-thread-multi/Socket.pm line 386.
    Thread 2 terminated abnormally: Bad arg length for Socket::pack_sockaddr_in, length is 0, should be 4 at /usr/lib/perl5/5.10.0/i586-linux-thread-multi/Socket.pm line 386.
    2 [error]
    Thread 3 terminated abnormally: Bad arg length for Socket::pack_sockaddr_in, length is 0, should be 4 at /usr/lib/perl5/5.10.0/i586-linux-thread-multi/Socket.pm line 386.

    ошибки вываливаются, я думаю надо поставить проверку на не пустое значение $ip что бы их небыло
     
  4. fry

    fry Elder - Старейшина

    Joined:
    7 Mar 2008
    Messages:
    25
    Likes Received:
    2
    Reputations:
    0
    То что ты делаешь наверное можно сделать простым форком.

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

    Теперь вот я что прочитал
    http://perldoc.perl.org/threads.html

    Как я понял, создаёться копия перла на каждый поток. Переменый не являються общими. И для скрипта это выглядит как форк.

    Вывод использовать форк проще всего или взять язык который разработан для правильной работы в потоками (умеет синхронизировать код)
     
  5. zer0ska

    zer0ska Elder - Старейшина

    Joined:
    5 Dec 2007
    Messages:
    103
    Likes Received:
    9
    Reputations:
    0
    !

    Вот что я своими силама накодил поправте если где ошибки )
    Code:
    #!/usr/bin/perl
    use threads;
    use Socket;
    
    %ipr = ('192.168.0.1' => '1',
    	'192.168.0.2' => '2',
    	'192.168.0.3' => '3');
    
    
    $p='135';
    
    $i =0;
    
    foreach $ip (keys %ipr){
    
    	socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
    	$thr[$i]=threads->create(\&test_connect, $ip, $p);
    
    	$iaddr = inet_aton($ip);
    	$paddr = sockaddr_in($p, $iaddr);
    	close(SOCK);
    	$i++;
    }
    
    sub test_connect {
    	$iaddr = inet_aton($ip);
            $paddr = sockaddr_in($p, $iaddr);
    	if(connect(SOCK, $paddr)) {
                    print $ip." [connect]\r\n";
    
    		return  $ip;
    
            }
            else {
                    print $ip." [error]\r\n";
                    return $ip;
            }
    
            # send (SOCK, "", 0);
    	return;
    }
    
     
  6. Kaimi

    Kaimi Well-Known Member

    Joined:
    23 Aug 2007
    Messages:
    1,732
    Likes Received:
    811
    Reputations:
    231
    Code:
    use warnings;
    use strict;
    use Socket;
    use threads;
    use threads::shared;
    
    my @trl;
    my $p = '135';
    my $threads = 2;
    my @ipr : shared = qw(192.168.1.1 192.168.1.2 192.168.1.3);
    
    for(0..$threads) {$trl[$_] = threads->create(\&check, $_);}
    for(@trl) { $_->join; }
    
    sub check {
    my $ip;
    while(@ipr) {
    	{lock(@ipr); $ip = shift(@ipr);}
    	socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
    	my $iaddr = inet_aton($ip);
    	my $paddr = sockaddr_in($p, $iaddr);
    	connect(SOCK, $paddr) ? (print "$ip [connect]\r\n") : (print "$ip [error]\r\n");
            close(SOCK);
    	}
    }
    
     
    _________________________
  7. biophreak

    biophreak Elder - Старейшина

    Joined:
    3 Aug 2007
    Messages:
    348
    Likes Received:
    63
    Reputations:
    15
    use warnings 'all';
    use strict;
    use diagnostics;
    и правь ;)
    PS: И не лучше-ли сделать цикл вне функции?
     
    #7 biophreak, 28 Oct 2008
    Last edited: 28 Oct 2008
  8. Spyder

    Spyder Elder - Старейшина

    Joined:
    9 Oct 2006
    Messages:
    1,388
    Likes Received:
    1,209
    Reputations:
    475
    fry, юзать форки для этой задачи не имеет смысла, куда проще и быстрее сделать всё с потоками
     
  9. zer0ska

    zer0ska Elder - Старейшина

    Joined:
    5 Dec 2007
    Messages:
    103
    Likes Received:
    9
    Reputations:
    0
    !

    Вот так сказать последняя версия :)
    Code:
    #!/usr/bin/perl
    use threads;
    use Socket;
    
    $p   = '139';
    $sip = '192.168.0.';
    
    for(1..255) {
    	$ip = '192.168.0.'.$_;
    	$thr[$_]=threads->create(\&conn, $ip, $p, SOCK)->join;
    	
    }
    sub conn {
    	socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
    	$iaddr = inet_aton($ip);
    	$paddr = sockaddr_in($p, $iaddr);
    	
    	if(connect(SOCK, $paddr)) {
                    print $ip."\r\n";
                    close(SOCK);
    		return;
    
            }
            else {
            	close(SOCK);
    		return;
            }
    
            # send (SOCK, "", 0);
    	return;
    }
    
    
    посоветуйте как по грамотней распределять потоки потому что диапазон может быть не только от 0 до 255 но и больше а создавать 1000 потоков имхо не есть гуд )
    Как лучше создовать сокет внутри фнкции или создать один а в функции юзать только connect ?
     
  10. zythar

    zythar Elder - Старейшина

    Joined:
    16 Feb 2008
    Messages:
    517
    Likes Received:
    109
    Reputations:
    5
    ну дак ты попробуй и тем и другим способом. посмари в каком случае быстрее с помощью time-a и сделай так как тебе выгодно.
     
  11. zer0ska

    zer0ska Elder - Старейшина

    Joined:
    5 Dec 2007
    Messages:
    103
    Likes Received:
    9
    Reputations:
    0
    мне важна не только скорость но и нагрузка на сервер
    конечно это можно определить и опытным путём :)
     
  12. Spyder

    Spyder Elder - Старейшина

    Joined:
    9 Oct 2006
    Messages:
    1,388
    Likes Received:
    1,209
    Reputations:
    475
    ипы в массив и через шифт их извекаешь в каждом потоке, посмотре мой первый пост
     
  13. nerezus

    nerezus Banned

    Joined:
    12 Aug 2004
    Messages:
    3,191
    Likes Received:
    729
    Reputations:
    266
    Зачем какать, если можно выблевывать все через рот?

    Потому что:
    1. Какать через попу легче.
    2. У бодьшинства людей процесс выблевывания сопровождается неприятными ощущениями и не всегда протекает гладно.
    3. Выблевывание менее гигиенично.
    4. После выблевывания недостаточно вытереть рот - придется выполнять специальные процедуры для прочистки.
    5. Выблевывание сопровождается потерей соли в организме.
    6. Какать - более гибко. Какание происходит по типу логичный queue, в то время как для выблевывания приходится юзать неуместный stack и верхние элементы его будут необработаны.
     
    2 people like this.
  14. Spyder

    Spyder Elder - Старейшина

    Joined:
    9 Oct 2006
    Messages:
    1,388
    Likes Received:
    1,209
    Reputations:
    475
    5. Выблевывание сопровождается потерей соли в организме.

    спасибо, не знал
     
  15. KSURi

    KSURi tnega AOLPS

    Joined:
    6 Jun 2006
    Messages:
    458
    Likes Received:
    219
    Reputations:
    357
    Но кстати после выблевывания обычно полегче становится
     
  16. biophreak

    biophreak Elder - Старейшина

    Joined:
    3 Aug 2007
    Messages:
    348
    Likes Received:
    63
    Reputations:
    15
    Чем после выкакивания? :) Не факт :)