Runtime.exec(comando...) Muito lento!

Estou tendo sérios problemas com lentidão na hora de executar um aplicativo externo feito em C++. Em linha de comando o aplicativo demora cerca de 5 ms na sua execução, enquanto no Java demora longos 17 ms, são 12 ms a mais! (isso cresce proporcionalmente quando se aumenta a complexidade das operações) pq essa chamada pelo java demora tanto?!

eu estou usando o:

Process p = Runtime.getRuntime().exec("chamada para meu programa"); p.waitFor(); //para esperar a execução do programa...

pq demora tanto assim? eu notei que demora muito quando eu executo na primeira vez, depois ele se torna um POUCO mais rápido.

Experimente ler completamente os fluxos de saída do seu programa antes do waitFor.
Já tive muitos problemas com executáveis que escrevem no console, e demoram muito mais caso ele não seja lido (isso é, caso o java não leia o outputstream do processo).

ViniGodoy, obrigado pela sugestão mas eu já fiz isso… recuperando a saida do programa e o que eu notei, eh que ele demora excessivamente para mostrar algo (enquanto na linha de comando é rapido). O que eu acho eh que ele demora para chamar o programa para sua execução… mas a diferença é muito grande e preocupante.

Estranho, porque já usei esse comando diversas vezes e nunca tive esse tipo de lentidão.
Eu fazia a criação através do ProcessBuilder, mas acho que não deve haver muita diferença.

[quote=ViniGodoy]Estranho, porque já usei esse comando diversas vezes e nunca tive esse tipo de lentidão.
Eu fazia a criação através do ProcessBuilder, mas acho que não deve haver muita diferença.[/quote]

vc poderia me mostrar como fazia? as vezes pode ser diferente da minha maneira… aceito sugestões de alternativas pra eu testar

[quote=ViniGodoy]Experimente ler completamente os fluxos de saída do seu programa antes do waitFor.
Já tive muitos problemas com executáveis que escrevem no console, e demoram muito mais caso ele não seja lido (isso é, caso o java não leia o outputstream do processo).[/quote]

seria dessa forma que vc fala?

String line; Process p = Runtime.getRuntime().exec ("meu comandoo"); BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); while ((line = input.readLine()) != null) { System.out.println(line);}

Não, não. Eu criei uma classe para ler o processo:
http://www.guj.com.br/posts/list/213361.java#1087285

E também não esperava necessariamente por um \n, já que ele pode não ocorrer.

Aliás, se vc quiser redirecionar a saída de seu processo para um JTextComponent, essas classes também vão te interessar:
http://www.guj.com.br/posts/list/83462.java#445238 (veja esse post e o que está abaixo dele).

[quote=ViniGodoy]Não, não. Eu criei uma classe para ler o processo:
http://www.guj.com.br/posts/list/213361.java#1087285

E também não esperava necessariamente por um \n, já que ele pode não ocorrer.[/quote]

humm vou testar, soh uma dúvida, essa sua classe mostraria o que o console está escrevendo? no meu caso nem preciso… eu soh quero executar o programa externo e depois que ele acabar a execução, e continuar o código java. De forma rápida eh claro =]

Ele redireciona para um PrintWriter ou OutputStream qualquer.

Se você não quiser imprimir nada, simplesmente crie um DummyOutputStream (um filho de OutputStream com todos os métodos implementados em branco), e jogue ele como parâmetro para a classe. Eu tinha um desse no meu projeto.

Ele redireciona para um PrintWriter ou OutputStream qualquer.

Se você não quiser imprimir nada, simplesmente crie um DummyOutputStream (um filho de OutputStream com todos os métodos implementados em branco), e jogue ele como parâmetro para a classe. Eu tinha um desse no meu projeto.[/quote]

Entendi… vou testar isso para ver se ganho performance, qualquer coisa eu posto aqui novamente. Obrigado pelos esclarecimentos e dicas.

Olá VIniGodoy, eu implementei a sua classe e tentei utilizar, porém ele não está me mostrando a saída no console como esperado, além de não dar diferença alguma no tempo… (ainda continua mesma coisa)

estou fazendo o seguinte para chamar:

Process p = Runtime.getRuntime().exec("/bjin/" + bjin + "/query.bat"); System.out.println("executando......"); StreamRedirector stream = new StreamRedirector(System.out, p.getInputStream()); p.waitFor(); stream.stopRedirect();

onde meu comando está escrito em um bat. Ele deveria imprimir na tela saidas, mas ele não o faz utilizando a sua classe. Estou utilizando de modo erronio?

Ao executar seu programa em uma batch, o programa “cmd.exe” também é carregado.
E se houver algum antivírus, o programa antivírus também irá inspecionar (e reinspecionar) o arquivo .bat e o arquivo .exe.
Porventura é possível você rodar o seu programa diretamente sem a batch?

Dica: normalmente programas costumam demorar mais para rodarem se algum antivírus estiver ativo e estiver inspecionando os diretórios usados pelo seu programa. Se você consegue configurar seu antivírus de modo que ele não inspecione os diretórios usados pelo seu programa, talvez melhore um pouco o desempenho.

[quote=entanglement]Ao executar seu programa em uma batch, o programa “cmd.exe” também é carregado.
E se houver algum antivírus, o programa antivírus também irá inspecionar (e reinspecionar) o arquivo .bat e o arquivo .exe.
Porventura é possível você rodar o seu programa diretamente sem a batch?

Dica: normalmente programas costumam demorar mais para rodarem se algum antivírus estiver ativo e estiver inspecionando os diretórios usados pelo seu programa. Se você consegue configurar seu antivírus de modo que ele não inspecione os diretórios usados pelo seu programa, talvez melhore um pouco o desempenho. [/quote]

a operação realizada aqui é em ambiente linux, em uma máquina sem antivirus. Vou verificar a possibilidade de roda-lo sem o batch, pois o meu comando tem muitos parametros e estou com medo do exec não executar corretamente…

Ah, mas no caso do Linux, não vale a pena você rodar um script sem o interpretador de comandos. Isso é porque o interpretador de comandos (/bin/bash) já está carregado na memória, e diferentemente do Windows, se um programa já está carregado na memória, o tempo para iniciá-lo é desprezível.

[quote=anderson_lp789][quote=ViniGodoy]Não, não. Eu criei uma classe para ler o processo:
http://www.guj.com.br/posts/list/213361.java#1087285

E também não esperava necessariamente por um \n, já que ele pode não ocorrer.[/quote]

humm vou testar, soh uma dúvida, essa sua classe mostraria o que o console está escrevendo? no meu caso nem preciso… eu soh quero executar o programa externo e depois que ele acabar a execução, e continuar o código java. De forma rápida eh claro =][/quote]

Quando utilizei a classe StreamGobbler, ele foi corretamente… deu até uma certa melhora, mas o que eu percebi que ficou instavel. Tem vez que a execução é normal, como se fosse na linha de comando, mas em outros casos a demora é a mesma. Inacreditavel essa perda sem explicação… to me decepcionando com o java nessa parte :x

Cara, se você não precisa de nenhum retorno desse script (nem mesmo de um código de erro), pode tentar redirecionar a entrada e a saída de erro e a saída padrão (pode usar outro script para chamar esse script, que é mais fácil e é virtualmente tão rapido quanto chamar diretamente o programa).

Algo como escrever um outro script, cujo conteúdo é:

/seu/script > /dev/nul 2> /dev/nul < /dev/nul

[quote=entanglement]Cara, se você não precisa de nenhum retorno desse script (nem mesmo de um código de erro), pode tentar redirecionar a entrada e a saída de erro e a saída padrão (pode usar outro script para chamar esse script, que é mais fácil e é virtualmente tão rapido quanto chamar diretamente o programa).

Algo como escrever um outro script, cujo conteúdo é:

/seu/script > /dev/nul 2> /dev/nul < /dev/nul

[/quote]

humm não entendi muito bem a idéia. Seria redirecionar todo tipo de saida do programa externo para o SO? poderia me dar um exemplo melhor?
de qualquer forma vou testar isso, porém só tenho condições de testar na segunda, no laboratório da faculdade. Obrigado pela sugestão. Outra pergunta, como isso ficaria em ambiente windows?

é gente, a situação está tensa…

o software em C++ que executa comandos com uma média de 3 segundos via linha de comando, sendo chamado externo pelo java demora cerca de 80 segundos!! é uma diferença brutal! tem vezes que fica bem rápido, mas a maioria é muito lento… eu reparei que é lento na chamada e na finalização do programa.

Por favor alguém tem mais dicas? eu estou usando a classe Globber para pegar a saída… ele deixou bem instável, tem vez que fica rápido ou não. Meu projeto depende disso funcionar direito =/

ViniGodoy alguma dica mais? porque será que nada acontece quando utilizo sua classe?