<html><head><style type="text/css"><!-- DIV {margin:0px;} --></style></head><body><div style="font-family:times new roman,new york,times,serif;font-size:12pt;color:#000000;"><div>Olá,<br><br>Estou trabalhando com perl há alguns meses e recentemente me deparei com um grande desafio.(pelo menos para mim).<br>Não sei se esta lista é a adequada, mas ja gastei 4 semanas pesquisando no google e nada de solução.<br><br>Enfim...<br>Preciso reduzir o tempo de execução de um script de aproximadamente 50 minutos para 8 minutos.<br>1 - Este scrip faz mais de 2 mil "chamadas externas" de sistema operacional ( `comando` ) com timeout de 5 a 10 seguntos.<br>2 - É necessário processar o STDOUT e EXIT STATUS do comando <span style="text-decoration: underline;">em um processo único</span> não necessáriamente em sequencia.<br><br>A solução com certeza deve implementar alguma forma de paralelismo.<br>Não consegui desenvolver uma forma de utilizar "open" no
script. Então perdi para uma solução de baixo nível.<br><br>Encontrei uma solução que quase atendeu minhas expectativas, mas estou com problemas de nível de Sistema Operacional nela.<br><br>Recomendo que deem uma olhada no código pois agora irei descrever o problema deste código.<br><br>O meu problema é a ocorrencia de grande quantidade de TIMEOUTs, isto é,
o processo pai não recebe/processa as respostas dos filhos.<br>
Separei as chamadas de sistema em grupos de 80 comandos.<br>Quando executo o script sem o sleep tanto no processo pai quanto no processo filho chego q ter mais de 50% de perda de respostas, (TIMEOUT)<br>Conforme adiciono tempo ao sleep no processo filho, consigo reduzir a quantidade de TIMEOUTS considerávelmente, mas longe do satizfatório.<br>Já quando adiciono o sleep antes do fork do processo filho a ocorrencia de TIMEOUTs cai a menos de 0.5%, mas o tempo de execução do script se aproxima do original (40 minutos).<br><br>Acredito que meu problema esteja no processamento do sinal (kill), mas também pode ser no pipe. Não acredito que seja no pipe pois não ocorre erros no syswrite e no sysread, etc.<br>Já estou quase certo de que terei que refazer tudo de outro jeito, mas estou sem idéias e preciso da opinião de pessoas mais experientes.<br><br>Então, agradeço desde já a atenção de vocês e espero susgestões para corrigir este script ou
para refazer de outro jeito.<br><br>Cordialmente,<br><br>Gabriel <br><br>ps: Ignorem erros de sintaxe e identação pois editei o codigo no corpo da mensagem.<br><br>#########################################################################################################<br> my $gotone;<br>sub doneit {<br> $gotone=$gotone+1;<br># logMsg("Got one! ($gotone)");<br>} <br><br>$SIG{USR1} = \&doneit;<br>my $parent = $$;<br>$kids=0;<br>$gotone=0;<br><br>#Para não sobrecarregar o servidor, a lista de comandos é dividida em grupos de 80. (@CHECKS = (cmd1 .. cmd80)) <br>foreach my $checkID (@CHECKS) {<br> <br> pipe *{$checkID},PIPEN;<br><br> #Espera do processo pai antes de cada fork
para testes<br> # Este tempo de espera é diferencial na ocorrencia da falha<br>
# sleep(10);<br><br> $PIDs{$checkID} = fork();<br> if (not defined $PIDs{$checkID}) {<br> logMsg("ERROR: Fork FAILURE!!!");<br><br> } elsif ($PIDs{$checkID} == 0) {<br> # Processo filho executa espera diminuindo probalidade de sobrecarga de respostas para processo pai. <br> my $random_number = rand();<br>
# my $random_wait = $random_number*3;<br>
sleep($random_wait);<br><br> my $saida;<br> $saida = `cmdN`;<br> my $exit_value = $? >> 8;<br><br> #Escreve saida no pipe para processo pai.<br> my $write = syswrite PIPEN, "$exit_value;$saida";<br> if (!defined($write)) { <br> logMsg("ERROR (write pipe): $!"); <br>
}<br><br> close *{$checkID};<br> kill "USR1",$parent;<br> exit();<br> # fim do processo filho<br> } else {<br> # Contagem de número de processos filhos no pai (80)<br> $kids++;<br> } <br> }<br><br> # While para processamento de respostas dos processos filhos<br> # deve
ser garantido que todos filhos serão processados<br> while ($kids > 0) {<br><br> # Aguarda 10 segundos depois de receber ultimo sinal (USR1). $gotone é uma variavel global que contabiliza o numero de processos filhos que ja responderam. Esta variavel é decrementada de acordo com o processamento dos filhos para controle de TIMEOUT.<br> my $timeout = 10;<br> # While para espera de resposta/sinal de processos filhos<br> while ( $gotone < 1 && $timeout > 0) {<br> sleep 1;<br> $timeout=$timeout-1;<br>
}<br><br> # if para encerrar processamento. Informa número de processos filhos que não responderam. <br> # teoricamente este if nunca deve ser processado. ESTE É O PROBLEMA.<br> if ($timeout <= 0) { <br> logMsg("TIMEOUT!!! $kids checks não responderam a tempo.");<br> $kids =0;<br> next;<br> }<br><br> <br>
$gotone=$gotone-1;<br> <br> #for para saber qual filho respondeu (sysread irá falhar até encontrar) <br> foreach my $checkID (@CHECKS) {<br><br> my $win = "";<br> my $rin = $win;<br> vec($rin, fileno(*{$checkID}), 1) = 1;<br> my $ein = $rin ;<br> if (select($rin,$win,$ein,0)) {<br> my $response;<br>
my $read = sysread($checkID,$response,512);<br> #if (!defined($read)) { <br> # logMsg("ERROR (read pipe): $!"); <br> #}<br> #else { next;}<br><br> my $saida="";<br> my $exit_value="";<br> ($exit_value,$saida) =
split(';',$response);<br> $saida =~ s/[\r\n]//g;<br> $saida = $saida; <br><br> # Executa processamento da resposta<br><br> close *{$checkID};<br> $kids=$kids-1;<br> last;<br> }<br> }<br> }<br>
my $kid;<br> do {<br> $kid = waitpid(-1, WNOHANG);<br> } while $kid > 0;<br> } <br><br><br><br><br><br><br><br></div>
</div><br>
<hr size=1>Veja quais são os assuntos do momento no Yahoo! + Buscados: <a href="http://br.rd.yahoo.com/mail/taglines/mail/*http://br.maisbuscados.yahoo.com/">Top 10</a> - <a href="http://br.rd.yahoo.com/mail/taglines/mail/*http://br.maisbuscados.yahoo.com/celebridades/">Celebridades</a> - <a href="http://br.rd.yahoo.com/mail/taglines/mail/*http://br.maisbuscados.yahoo.com/m%C3%BAsica/">Música</a> - <a href="http://br.rd.yahoo.com/mail/taglines/mail/*http://br.maisbuscados.yahoo.com/esportes/">Esportes</a></body></html>