Fiz uns testes aqui no meu super lento notebook q acho q pode interessar:<br><br><br>fernando@fernando-laptop:~$ cat <a href="http://test_threads.pl">test_threads.pl</a> <br>#!/usr/bin/perl<br><br>use 5.10.0;<br>use strict;<br>

use Time::HiRes qw/gettimeofday tv_interval usleep/;<br><br>use threads (&#39;yield&#39;,<br>             &#39;stack_size&#39; =&gt; 16384,<br>             &#39;exit&#39; =&gt; &#39;threads_only&#39;,<br>             &#39;stringify&#39;);<br>

use threads::shared;<br><br>my @ips    : shared;<br>my %result : shared;<br>my $time   : shared;<br><br>$| = 1;<br><br>@ips = 1 .. 10_000;<br>my $ips = @ips;<br>say &quot;ips: $ips&quot;;<br>my $max_threads = shift || 200;<br>

<br>my $t0 = [gettimeofday];<br>push my @thrs, create_thread() for 1 .. $max_threads;<br>say &quot;Levou &quot;, tv_interval($t0, [gettimeofday]), &quot; seg para startar $max_threads threads&quot;;<br>say &quot;Media de tempo p/ startar cada thread: &quot;, $time / $max_threads;<br>

<br>print(&quot;\rtestados: &quot;, scalar keys %result), usleep 100 while @ips and $ips != scalar keys %result;<br>print $/;<br><br>my %r;<br>$r{ $_  }++ for values %result;<br>say &quot;$_: $r{ $_ }&quot; for qw/OK NOK/;<br>

say &quot;TOTAL: &quot;, $r{ OK } + $r{ NOK };<br><br>sub create_thread {<br>   threads-&gt;create({context =&gt; &quot;void&quot;}, \&amp;sub_thread, [gettimeofday]);<br>}<br><br>sub sub_thread {<br>   my $t0 = shift;<br>

   my $time_unit = tv_interval($t0, [gettimeofday]);<br>   my $tid = threads-&gt;tid;<br>   say $tid, &quot;: &quot;, $time_unit if $tid &gt;= $max_threads - 5;<br>   $time += $time_unit;<br><br>   while(my $ip = shift @ips) {<br>

      my $r = int rand 9;<br>      sleep 1 unless $r % 2;<br>      $result{ $ip } = $r % 2 ? &quot;OK&quot; : &quot;NOK&quot;;<br>   }<br>   exit;<br>}<br>fernando@fernando-laptop:~$ diff <a href="http://test_threads.pl">test_threads.pl</a> <a href="http://test_forks.pl">test_forks.pl</a> <br>

7c7<br>&lt; use threads (&#39;yield&#39;,<br>---<br>&gt; use forks   (&#39;yield&#39;,<br>11c11<br>&lt; use threads::shared;<br>---<br>&gt; use forks::shared;<br>fernando@fernando-laptop:~$ time ./<a href="http://test_threads.pl">test_threads.pl</a> 100<br>

ips: 10000<br>95: 0.009266<br>96: 0.006097<br>97: 0.011582<br>98: 0.007523<br>99: 0.006502<br>100: 0.022716<br>testados: 99030seg para startar 100 threads<br>OK: 4509<br>NOK: 5395<br>TOTAL: 9904<br>Perl exited with active threads:<br>

    85 running and unjoined<br>    15 finished and unjoined<br>    0 running and detached<br><br>real    0m55.945s<br>user    0m48.159s<br>sys    0m0.596s<br>fernando@fernando-laptop:~$ time ./<a href="http://test_threads.pl">test_threads.pl</a> 500<br>

ips: 10000<br>495: 0.005923<br>496: 0.151628<br>497: 1.154306<br>498: 0.005588<br>499: 0.005505<br>500: 0.006324<br>Levou 33.697717 seg para startar 500 threads<br>Media de tempo p/ startar cada thread: 0.06719761<br><br>

OK: 4420<br>NOK: 5580<br>TOTAL: 10000<br>Perl exited with active threads:<br>    0 running and unjoined<br>    500 finished and unjoined<br>    0 running and detached<br><br>real    0m38.136s<br>user    0m2.640s<br>sys    0m0.856s<br>

fernando@fernando-laptop:~$ time ./<a href="http://test_threads.pl">test_threads.pl</a> 1000<br>ips: 10000<br>995: 0.125149<br>996: 0.687834<br>997: 0.164103<br>998: 0.00555<br>999: 0.00544<br>1000: 0.005672<br>Levou 133.962833 seg para startar 1000 threads<br>

Media de tempo p/ startar cada thread: 0.132355601<br><br>OK: 4385<br>NOK: 5615<br>TOTAL: 10000<br>Perl exited with active threads:<br>    0 running and unjoined<br>    1000 finished and unjoined<br>    0 running and detached<br>

<br>real    2m28.914s<br>user    0m4.620s<br>sys    0m1.412s<br>fernando@fernando-laptop:~$ time ./<a href="http://test_forks.pl">test_forks.pl</a> 100<br>ips: 10000<br>95: 0.600199<br>96: 0.463332<br>97: 0.462497<br>98: 0.012093<br>

99: 1.848478<br>100: 0.273546<br>Levou 80.618404 seg para startar 100 threads<br>Media de tempo p/ startar cada thread: 0.81342024<br>testados: 9671<br>OK: 4417<br>NOK: 5583<br>TOTAL: 10000<br>Perl exited with active threads:<br>

    2 running and unjoined<br>    98 finished and unjoined<br>    0 running and detached<br><br>real    3m37.531s<br>user    0m30.998s<br>sys    0m9.469s<br>fernando@fernando-laptop:~$ <br><br><br>Sendo q no forks meu load chegou a 53...<br>

<br><br clear="all">Just another Perl Hacker,<br>Fernando (SmokeMachine)<br><a href="http://perl-e.org">http://perl-e.org</a><br>
<br><br><div class="gmail_quote">Em 10 de julho de 2010 12:50, João André Simioni <span dir="ltr">&lt;<a href="mailto:jasimioni@gmail.com">jasimioni@gmail.com</a>&gt;</span> escreveu:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">

Fiz um teste agora colocando um sleep 10 no inicio da função checkIp.<br>
As threads abrem rápido assim, mas o desempenho ficou ruim. Além<br>
disso, notei que as threads não utilizam os demais processadores.<br>
<br>
Minha solução atual está com um fork no começo, quebrando o código em<br>
8 processos distintos (número de processadores), cada processo com um<br>
sub-grupo e criando suas threads (30 threads por grupo).<br>
<br>
Obrigado pela ajuda<br>
<br>
João André<br>
<br>
2010/7/10 João André Simioni &lt;<a href="mailto:jasimioni@gmail.com">jasimioni@gmail.com</a>&gt;:<br>
<div><div></div><div class="h5">&gt; Blabos,<br>
&gt;<br>
&gt; o loop interno não é nem usado nesse código, como observado pelo<br>
&gt; Bruno, porque ele define a quantidade de threads no início. Usualmente<br>
&gt; eu disparo uma thread para cada elemento que vou gerenciar, e defino<br>
&gt; um limite de threads abertas no início do código e é por isso que esse<br>
&gt; loop existe, para controlar o limite de threads (e funciona bem em<br>
&gt; diversos outros scripts que não têm o mesmo problema de desempenho).<br>
&gt;<br>
&gt; Segue os comentários no código:<br>
&gt;<br>
&gt;&gt; #!/usr/bin/perl<br>
&gt;&gt;<br>
&gt;&gt; use strict;<br>
&gt;&gt; use DBI;<br>
&gt;&gt; use Net::Ping;<br>
&gt;&gt; use Time::HiRes qw/usleep tv_interval gettimeofday/;<br>
&gt;&gt; use threads (&#39;yield&#39;, &#39;stack_size&#39; =&gt; 32*4096, &#39;exit&#39; =&gt;<br>
&gt;&gt; &#39;threads_only&#39;, &#39;stringify&#39;);<br>
&gt;&gt;<br>
&gt;&gt; my $host = &#39;192.168.160.179&#39;;<br>
&gt;&gt; my $sid  = &#39;HOMOLOG&#39;;<br>
&gt;&gt; my $user = &#39;mac_user&#39;;<br>
&gt;&gt; my $pass = &#39;mac_user&#39;;<br>
&gt;&gt;<br>
&gt;&gt; my $dbh = DBI-&gt;connect(&quot;dbi:Oracle:host=$host;sid=$sid&quot;, $user, $pass,<br>
&gt;&gt; { AutoCommit =&gt; 1 });<br>
&gt;&gt;<br>
&gt;&gt; my $sth = $dbh-&gt;prepare(&#39;SELECT CPE_ID, CLIENTE_ID, CPE_DESC,<br>
&gt;&gt; CPE_IP_WAN, CPE_NODE, CPE_IF FROM MAC_CPE WHERE CPE_PING = ? AND<br>
&gt;&gt; CPE_ATIVO = ?&#39;);<br>
&gt;&gt; $sth-&gt;execute(&#39;1&#39;, &#39;A&#39;);<br>
&gt;&gt;<br>
&gt;&gt; my @cpes;<br>
&gt;&gt;<br>
&gt;&gt; while (my (@row) = $sth-&gt;fetchrow_array) {<br>
&gt;&gt;     push @cpes, [ @row ];<br>
&gt;&gt; }<br>
&gt;&gt;<br>
&gt;&gt; $dbh-&gt;disconnect();<br>
&gt;<br>
&gt; Até aqui somente listei os elementos a partir do banco de dados.<br>
&gt;<br>
&gt; O código abaixo quebra o numero de elementos em 250 threads.<br>
&gt;<br>
&gt;&gt; my $maxThreads = 250;<br>
&gt;&gt; my $total      = @cpes;<br>
&gt;&gt;<br>
&gt;&gt; my $cpePerThread = int($total / $maxThreads);<br>
&gt;&gt;<br>
&gt;&gt; my @toMonitor;<br>
&gt;&gt; my $i = 0;<br>
&gt;&gt; my $c = 0;<br>
&gt;&gt;<br>
&gt;&gt; foreach my $cpe (@cpes) {<br>
&gt;&gt;     push @{$toMonitor[$i]}, $cpe;<br>
&gt;&gt;     $c++;<br>
&gt;&gt;<br>
&gt;&gt;     if ($c &gt; $cpePerThread) {<br>
&gt;&gt;         $i++;<br>
&gt;&gt;         $c = 0;<br>
&gt;&gt;     }<br>
&gt;&gt; }<br>
&gt;&gt;<br>
&gt;&gt; print &quot;Para $total cpes, e $maxThreads threads, tenho no final $i<br>
&gt;&gt; grupos, com &quot;, scalar @{$toMonitor[0]}, &quot; elementos cada\n&quot;;<br>
&gt;<br>
&gt;<br>
&gt;<br>
&gt; E imprimo - vou ter o total de elementos dividido em 250 grupos (cada<br>
&gt; grupo atendido por uma thread)<br>
&gt;<br>
&gt;<br>
&gt;<br>
&gt;&gt; sub processResult {<br>
&gt;&gt;     my $r = shift;<br>
&gt;&gt;     if (ref $r ne &#39;ARRAY&#39;) {<br>
&gt;&gt;         print STDERR &quot;Erro na thread\n&quot;;<br>
&gt;&gt;         return 0;<br>
&gt;&gt;     }<br>
&gt;&gt;     my ($result, $host, $ifs) = @$r;<br>
&gt;&gt;<br>
&gt;&gt; }<br>
&gt;<br>
&gt; Funcao de processamento do resultado da thread -- aqui não faz nada<br>
&gt;<br>
&gt;&gt; sub testeClient {<br>
&gt;&gt;     my $threadNum = shift;<br>
&gt;&gt;     my $cpeGroup  = shift;<br>
&gt;&gt;     foreach my $cpe (@{$cpeGroup}) {<br>
&gt;&gt;         my ($cpeId, $clientId, $cpeDesc, $cpeIp, $cpeNode, $cpeIf) = @$cpe;<br>
&gt;&gt;         my $pingOk = &amp;checkIp($cpeIp);<br>
&gt;&gt;         my $status = $pingOk ? &#39;RESPONDE&#39; : &#39;MORTO&#39;;<br>
&gt;&gt;         # print join(&quot;, &quot;, $threadNum, $cpeId, $clientId, $cpeDesc,<br>
&gt;&gt; $cpeIp, $cpeNode, $cpeIf, $status), &quot;\n&quot;;<br>
&gt;&gt;     }<br>
&gt;&gt;     # print &quot;Finishing thread $threadNum\n&quot;;<br>
&gt;&gt;     return([1, 0]);<br>
&gt;&gt; }<br>
&gt;<br>
&gt; Código da thread - basicamente chama a sub &#39;checkIp&#39; para ver se o<br>
&gt; host está vivo.<br>
&gt;<br>
&gt; Abaixo o código de criação das threads - para cada grupo, cria uma thread.<br>
&gt;<br>
&gt;&gt; my $threadCount = 1;<br>
&gt;&gt; foreach my $cpeGroup (@toMonitor) {<br>
&gt;&gt;     print &quot;Trying to create thread&quot;;<br>
&gt;&gt;     my $t0 = [gettimeofday];<br>
&gt;&gt;<br>
&gt;&gt;     print &quot; in &quot;, scalar localtime $t0-&gt;[0], &quot;.&quot;, $t0-&gt;[1], &quot;\n&quot;;<br>
&gt;&gt;<br>
&gt;&gt;     my $thr = threads-&gt;create({scalar =&gt; &#39;1&#39;}, &#39;testeClient&#39;,<br>
&gt;&gt; $threadCount, $cpeGroup);<br>
&gt;&gt;     my $elapsed = tv_interval ( $t0, [gettimeofday]);<br>
&gt;&gt;     print &quot;Created thread $thr ($threadCount) - took $elapsed seconds<br>
&gt;&gt; to create\n&quot;;<br>
&gt;&gt;     $threadCount++;<br>
&gt;<br>
&gt; Esse bloco pode ser removido, pois nunca entra - foi a primeira coisa<br>
&gt; que tirei, porque achei que a chamada a threads-&gt;list poderia estar<br>
&gt; influenciando. Esse método retorna em menos de 1ms em todas as<br>
&gt; execuções. Mas se preferir só ignora.<br>
&gt;<br>
&gt;&gt;     while (threads-&gt;list() &gt;= $maxThreads) {<br>
&gt;&gt;         my @joinable = threads-&gt;list(threads::joinable);<br>
&gt;&gt;         for (@joinable) {<br>
&gt;&gt;             my $r = $_-&gt;join();<br>
&gt;&gt;             &amp;processResult($r);<br>
&gt;&gt;         }<br>
&gt;&gt;         usleep(10000);<br>
&gt;&gt;     }<br>
&gt;&gt;     my $elapsed = tv_interval ( $t0, [gettimeofday]);<br>
&gt;<br>
&gt; Finaliza a criação de threads<br>
&gt;<br>
&gt;&gt; }<br>
&gt;<br>
&gt; Aguarda as threads concluirem.<br>
&gt;<br>
&gt;&gt; while (threads-&gt;list()) {<br>
&gt;&gt;     my @joinable = threads-&gt;list(threads::joinable);<br>
&gt;&gt;     for (@joinable) {<br>
&gt;&gt;         my $r = $_-&gt;join();<br>
&gt;&gt;         &amp;processResult($r);<br>
&gt;&gt;     }<br>
&gt;&gt;     usleep(10000);<br>
&gt;&gt; }<br>
&gt;<br>
&gt; Fim de execução<br>
&gt;<br>
&gt;&gt; sub checkIp {<br>
&gt;&gt;     my $ip = shift;<br>
&gt;&gt;     my $pingOk = 0;<br>
&gt;<br>
&gt;<br>
&gt; Essa rotina faz 3 testes para cada elemento. Em cada teste, tenta um<br>
&gt; ping ICMP, um UDP e um TCP. Tenho que executar o ping do S.O. porque<br>
&gt; senão sou obrigado a rodar o script como root e o Net::Ping faz<br>
&gt; confusão com o ICMP. Se eu testo um host e ele nao responde no tempo<br>
&gt; de timeout e eu em seguida testar outro host, se o primeiro responder<br>
&gt; ele acha que o segundo respondeu.<br>
&gt;<br>
&gt;&gt;     eval {<br>
&gt;&gt;         for (1..3) {<br>
&gt;&gt;             my $ping = `/bin/ping -c 1 -w 1 $ip`;<br>
&gt;&gt;<br>
&gt;&gt;             if (grep { / 0% packet loss/ } $ping) {<br>
&gt;&gt;                 $pingOk = 1;<br>
&gt;&gt;                 return 1;<br>
&gt;&gt;             }<br>
&gt;&gt;<br>
&gt;&gt;             if ($pingOk == 0) {<br>
&gt;&gt;                 my $p = Net::Ping-&gt;new(&#39;icmp&#39;);<br>
&gt;&gt;                 $p-&gt;service_check(1);<br>
&gt;&gt;                 if ($p-&gt;ping($ip, 1)) {<br>
&gt;&gt;                     $pingOk = 1;<br>
&gt;&gt;                     return 1;<br>
&gt;&gt;                 }<br>
&gt;&gt;             }<br>
&gt;&gt;<br>
&gt;&gt;             if ($pingOk == 0) {<br>
&gt;&gt;                 my $p = Net::Ping-&gt;new(&#39;udp&#39;);<br>
&gt;&gt;                 $p-&gt;service_check(1);<br>
&gt;&gt;                 if ($p-&gt;ping($ip, 1)) {<br>
&gt;&gt;                     $pingOk = 1;<br>
&gt;&gt;                     return 1;<br>
&gt;&gt;                 }<br>
&gt;&gt;             }<br>
&gt;&gt;<br>
&gt;&gt;             sleep 3;<br>
&gt;&gt;         }<br>
&gt;&gt;     };<br>
&gt;&gt;<br>
&gt;&gt;     return $pingOk;<br>
&gt;&gt; }<br>
&gt;&gt;<br>
&gt;<br>
&gt; Quanto a usar Java, é que tenho um grupo de desenvolvimento Java do<br>
&gt; meu lado - eu posso solicitar a eles, mas eu não vejo porque Perl não<br>
&gt; pode atender bem nesse caso.<br>
&gt;<br>
&gt; Obrigado<br>
&gt;<br>
_______________________________________________<br>
Rio-pm mailing list<br>
<a href="mailto:Rio-pm@pm.org">Rio-pm@pm.org</a><br>
<a href="http://mail.pm.org/mailman/listinfo/rio-pm" target="_blank">http://mail.pm.org/mailman/listinfo/rio-pm</a><br>
</div></div></blockquote></div><br>