Outputdatareceived waitforexit
Outputdatareceived waitforexit
Obter através da App Store Leia esta publicação em nosso aplicativo!
Obtenha saída ao vivo do Processo.
Tenho um problema no meu projeto. Gostaria de iniciar um processo, 7z. exe (versão do console). Eu tentei três coisas diferentes:
Process. StandardOutput. ReadToEnd (); OutputDataReceived & amp; BeginOutputReadLine StreamWriter.
Nada funciona. Ele sempre "espera" no final do processo para mostrar o que eu quero. Eu não tenho nenhum código para colocar, apenas se você quiser meu código com uma das coisas listadas até lá. Obrigado.
Onde "processo" é o meu processo pré-fabricado.
Ok, eu sei por que isso não funciona corretamente: 7z. exe é o bug: exibe uma porcentagem de carga no console, e ele envia informações somente quando o arquivo atual está finalizado. Na extração, por exemplo, funciona bem :). Vou procurar outra maneira de usar as funções 7z sem 7z. exe (talvez com 7za. exe ou com alguma DLL). Obrigado a todos. Para responder à pergunta, o evento OuputDataRecieved funciona bem!
[Editar] Este é um exemplo de trabalho:
Btw, ls - R C: \ lista todos os arquivos da raiz de C: recursivamente. Estes são muitos arquivos, e tenho certeza que não é feito quando os primeiros resultados aparecem na tela. Existe a possibilidade de que 7zip mantenha a saída antes de mostrá-la. Eu não tenho certeza do que você me dá para o processo.
Eu não sei se alguém ainda está procurando por uma solução para isso, mas surgiu várias vezes para mim, porque estou escrevendo uma ferramenta na Unity em apoio de alguns jogos e devido à interoperabilidade limitada de certos sistemas com mono (como PIA para ler texto do Word, por exemplo), muitas vezes tenho que escrever executáveis específicos do sistema operacional (às vezes Windows, às vezes MacOS) e iniciá-los no Process. Start ().
O problema é que, quando você inicia um executável como este, ele será ativado em outro segmento que bloqueia seu aplicativo principal, causando um atraso. Se você quiser fornecer feedback útil aos seus usuários durante este período, além dos ícones de rotação evocados pelo seu sistema operacional, então você está meio ferrado. Usar um fluxo não funcionará porque o segmento ainda está bloqueado até a conclusão da execução.
A solução que eu acertei, o que pode parecer extremo para algumas pessoas, mas acho que funciona muito bem para mim, é usar sockets e multithreading para configurar comecções síncronas confiáveis entre os dois aplicativos. Claro, isso só funciona se você estiver criando ambas as aplicações. Caso contrário, acho que você não tem sorte. . Gostaria de ver se ele funciona com apenas multithreading usando uma abordagem de fluxo tradicional, então se alguém gostaria de tentar isso e publicar os resultados aqui que seria ótimo.
De qualquer forma, aqui está a solução que está funcionando para mim:
No principal, ou aplicativo de chamada, faço algo como isto:
Aqui eu estabeleço o servidor de soquete:
Aqui está o meu manipulador de soquete para o segmento. note que você terá que criar vários tópicos em alguns casos; é por isso que eu tenho essa lista _builderCommThreads lá (eu usei isso do código em outro lugar onde eu estava fazendo algo parecido, mas chamando várias instâncias em uma linha):
Claro, você precisará declarar algumas coisas no topo:
. então, no executável invocado, configure o outro lado (eu usei estabilidade neste caso, você pode usar o que quiser):
. Estou usando isso para iniciar uma ferramenta de linha de comando no Windows que usa o material do PIA para extrair o texto de um documento do Word. Eu tentei PIA o. dlls em Unity, mas encontrei problemas de interoperabilidade com mono. Também estou usando o MacOS para invocar scripts de shell que lançam instâncias Unity adicionais em batchmode e executem scripts de editor nas instâncias que conversam com a ferramenta em relação a essa conexão de soquete. É ótimo, porque agora posso enviar comentários ao usuário, depurar, monitorar e responder a etapas específicas do processo, etc., e assim por diante.
Para lidar corretamente com o redirecionamento de saída e / ou erro, você também deve redirecionar a entrada. Parece ser característica / erro no tempo de execução do aplicativo externo que você está iniciando e do que eu vi até agora, não é mencionado em nenhum outro lugar.
Utilizei a classe CmdProcessor descrita aqui em vários projetos com muito sucesso. Parece um pouco assustador no início, mas é muito fácil de usar.
Deixe o acima estar em um segmento.
Agora, para atualizar a saída para UI, você pode usar um temporizador com duas linhas.
Herança múltipla.
Derivado de muitas coisas.
O processo Async OutputDataReceived / ErrorDataReceived tem uma falha ao lidar com prompts.
Classe System. Diagnostics. Process - Parte 2.
Na Parte 1, discuti o problema em que usando o redirecionamento stdout / stderr e lendo-os de forma síncrona, o buffer de saída pode ficar cheio e bloquear o processo filho na próxima "gravação". Em seguida, ocorre um impasse porque o processo pai está aguardando que a criança saia antes de ler dados do buffer, a criança está bloqueando a gravação porque o buffer está cheio e, portanto, o impasse. A resposta é simples & # 8211; é melhor usar o método assíncrono de leitura de dados de stdout / stderr. Esta questão é previsível e foi minha mágoa.
Não sou eu, é você.
Eu me deparo com outra questão, que parecia o mesmo impasse, onde uma má pressuposição na implementação da classe Processo da Microsoft causou um tipo diferente de impasse entre os processos pai e filho. Eu achei quando meu processo filho me levou a afirmar a atividade solicitada, veja a Figura 1 para um exemplo.
O prompt terminou sem uma nova linha, deixando o cursor no final do prompt (o que faz sentido, por que o cursor seria configurado sob o prompt e não ao lado dele na tela). Veja a Figura 2, por exemplo, o código desse prompt.
O meu processo pai foi codificado para inspecionar os dados de stdout recebidos de forma assíncrona, procurando o prompt. Se / quando o prompt foi recebido, o processo pai emitiria uma resposta ao stdin do processo filho. Veja a Figura 3.
No entanto, quando executo meu processo pai e o processo filho enviou o prompt, o texto nunca veio no evento OutputDataReceived ... e meu processo pai estava sentado na linha p. WaitForExit () para sempre ... O processo Child estava aguardando uma resposta que nunca veio dos pais, e estávamos mais uma vez em um impasse, desta vez eu não era eu ... O problema não estava no meu código.
No NewLine, no DataReceivedEvent ...
Comecei a depurar e assistir os eventos OutputDataReceived e comecei a mudar o código de processo filho de várias maneiras. A alteração pequena abaixo causou o evento OutputDataReceived para disparar com o prompt de texto, veja a Figura 4.
De alguns outros testes, parece que o evento OutputDataReceived é acionado somente quando um NewLine está na saída do processo filho. Um prompt sem um NewLine não dispararia o evento OutputDataReceived e, portanto, o processo pai não obteve o prompt e não pode responder. Impasse!
Implementando minha própria leitura assíncrona de stdout / stderr.
Eu preciso ler prompts de um processo filho que não é meu código, mas um aplicativo de consola de terceiros, então, finalmente, eu precisava receber prompts com NewLines. Resolver o problema exigiu que eu implementei minha própria classe Async IO para ler o processo stdout / stderror.
Eu criei uma classe chamada StdStreamReader que lê um fluxo e desencadeia eventos basicamente semelhantes ao evento Processo OutputDataReceived, no entanto, ele não destrói uma NewLine para disparar um evento recebido de dados, mas em vez disso dispara assim que os dados são recebidos. Na Figura 5, destaquei as diferenças de código no código de processo Parent usando a nova classe de leitor.
O código para o StdStreamReader é bastante mundano, mas o resultado foi o esperado, veja a Figura 6.
Observe que "Sim" não foi exibido logo após o prompt - isso ocorre porque ele foi enviado diretamente para o processo filho stdin e não exibido.
Clique para o código fonte completo, que é fornecido "como está", sem garantia de qualquer tipo.
Compartilhar isso:
Relacionados.
Pós-navegação.
Deixe uma resposta Cancelar resposta.
Bom trabalho, esta é a solução exata que eu estava procurando. Obrigado por incluir seu código-fonte!
Agradeço um milhão, cara! Aparentemente, esta questão ainda é relevante após 4 anos. Me ajudou muito.
Esperando um processo com tempo limite em.
Na mesma linha da minha última publicação, podemos querer ser mais inteligentes sobre o lançamento de um processo e aguardamos a saída.
Particularmente, se esse processo for parte de um sistema crítico, como seu processo de compilação, você não quer que um processo suspenso seja capaz de fazer com que seu sistema de compilação inteiro pare de morrer nas suas faixas.
Felizmente, o Processo tem uma sobrecarga de WaitForExit que leva um tempo limite inteiro e retorna um booleano - verdadeiro se o processo for encerrado ou falso se o processo não acontecesse.
Usando esta função, podemos escrever um método como este:
Neste trecho, OutputDataReceived é um evento que dispara quando o processo grava dados em saída padrão e sinais BeginOutputReadLine para que configuramos nosso evento e estamos prontos para começar a ouvir a saída do processo.
Usar o formulário de evento neste caso significa que não precisamos ter o texto de saída completo do processo na memória em nenhum momento. À medida que o processo escreve uma linha de texto, teremos apenas essa linha na memória, e isso será coletado por lixo depois de atualizar nosso contador.
Há dois "gotcha" s neste trecho, no entanto.
O primeiro é process. Kill (). Esta é uma condição de corrida clássica - entre o tempo em que nosso processo retorna de process. WaitForExit () e invoca processo. Kill (), o processo de destino pode sair. Nesse caso, o MSDN afirma que, se você chamar. Kill () em um processo que já saiu, você receberá uma InvalidOperationException.
Podemos corrigir isso, manipulando a exceção, assim:
O segundo "gotcha" é muito sutil, e você provavelmente não o achará até que a função não retorne o resultado esperado, ou até se sentar e ler toda a página de documentação para Process. WaitForExit (int). O MDSN afirma que:
Quando a saída padrão foi redirecionada para manipuladores de eventos assíncronos, é possível que o processamento de saída não seja concluído quando esse método retornar. Para garantir que o tratamento de eventos assíncrono tenha sido concluído, chame a sobrecarga WaitForExit () que não leva nenhum parâmetro depois de receber uma verdade dessa sobrecarga.
Nesse caso, é possível que nossa função GetNumOutputChars devolva um valor que contenha menos caracteres do que a saída real do processo, a menos que chamemos WaitForExit () novamente.
Com isso em mente, nossa função de segurança final agora se parece com isto:
Usando Process. BeginOutputReadLine pode levar a linhas de stdout perdidas # 12219.
joelverhagen comentou 30 de setembro de 2018 e # 8226;
Ao escrever código que cria processos filho e precisa capturar stdout, descobri que as linhas de saída perdem a seguinte condição:
muito paralelismo. ProcessStartInfo. RedirectStandardOutput = true Process. OutputDataReceived + = CollectLines (ou seja, usando o fluxo assíncrono) Process. BeginOutputReadLine () Process. WaitForExit (int. MaxValue)
Observe que passar -1 (período de tempo infinito) para WaitForExit não faz com que as linhas desapareçam (com base em meus próprios testes).
Criei um pequeno aplicativo de demonstração para fazer isso. É repro na netlineapp1.0 e net45: processredirect. zip. Basta usar o dotnet run para experimentá-lo.
Dito isto, você pode capturar stdout usando Process. StandardOutput (que é um StreamReader). No entanto, para consumir isso de maneira assíncrona e segura você precisa usar threads / tarefas de fundo. Em outras palavras:
Acho que isso é um problema porque é muito fácil entrar nesta armadilha. Usar os eventos para capturar o resultado é muito conveniente, pois você não precisa se preocupar em criar threads ou tarefas de plano de fundo. Além disso, a internet recomenda esse método:
Eu apenas tentei isso no Windows, Framework 4.5 e Core (netcoreapp1.0). Além disso, toda essa informação está relacionada ao stdout, mas imagino que o stderr tem o mesmo problema. Minha informação de dotnet é:
joelverhagen comentou 30 de setembro de 2018.
Atualizei o aplicativo de teste para suportar sistemas que não sejam do Windows (usando o eco):
Os resultados são os mesmos para Windows, Linux e Mac OS X.
Use as propriedades StreamReader no Processo em vez de eventos, pois você pode perder a saída # 906.
stephentoub comentou 7 de outubro de 2018 e # 8226;
@joelverhagen, para melhor ou pior, o que você está vendo é um design documentado.
Esta sobrecarga garante que todo o processamento foi concluído, incluindo o tratamento de eventos assíncronos para saída padrão redirecionada. Você deve usar essa sobrecarga após uma chamada para a sobrecarga WaitForExit (Int32) quando a saída padrão foi redirecionada para manipuladores de eventos assíncronos.
E para Process. WaitForExit (Int32):
Quando a saída padrão foi redirecionada para manipuladores de eventos assíncronos, é possível que o processamento de saída não seja concluído quando esse método retornar. Para garantir que o tratamento de eventos assíncrono tenha sido concluído, chame a sobrecarga WaitForExit () que não leva nenhum parâmetro depois de receber uma verdade dessa sobrecarga.
Você pode ver aqui que o código explicitamente não aguarda a saída redirecionada para ser concluída se foi passado um tempo limite não-infinito:
Dito isto, não sei por que foi projetado desta forma.
Priya91 comentou 7 de dezembro de 2018.
@joelverhagen Usando WaitForExit sem tempo limite depois que a outra sobrecarga deve desbloqueá-lo, como indicado nos documentos. Ao fechar esta questão, reabra se for necessário assistência adicional.
&cópia de; 2018 GitHub, Inc. Termos Privacidade Segurança Status Ajuda.
Você não pode executar essa ação neste momento.
Você fez login com outra guia ou janela. Recarregue para atualizar sua sessão. Você se separou em outra guia ou janela. Recarregue para atualizar sua sessão.
process. OutputDataReceived ainda dispara mesmo após o processo teminado. # 432.
suwatch comentou 6 de março de 2018.
O sintoma relacionado.
Isso tem a ver com a implementação do Processo e seu fluxo assíncrono de saída. O cenário é que nós iniciamos o processo e escutamos em OutputDataReceived para capturar seu stdout. Nós chamamos process. WaitForExit e assumimos que depois que ele retorna verdadeiro (processo de significado encerrado), não deve haver nenhum evento mais disparado por OutputDataReceived.
Usando a reflexão, isso acaba por ser verdade se esperamos com -1 timeout (aguardará this. error. WaitUtilEOF () aka buffer to flush). Nosso intervalo de espera de implementação (5s) para permitir o gerenciamento ocioso. Essa espera pode retornar verdadeira mesmo que o OutputDataReceived ainda tenha saída pendente.
A saída esquerda foi disparada depois de nos fazer escrever para o mesmo registro xml como o segmento principal (assumindo que o processo foi concluído). O log xml fica corrompido como resultado da gravação simultânea.
conserte # 432 para aguardar a saída do processo # 433.
HenrikFrystykNielsen adicionou um compromisso a HenrikFrystykNielsen / kudu que referenciou esta questão 12 de março de 2018.
&cópia de; 2018 GitHub, Inc. Termos Privacidade Segurança Status Ajuda.
Você não pode executar essa ação neste momento.
Você fez login com outra guia ou janela. Recarregue para atualizar sua sessão. Você se separou em outra guia ou janela. Recarregue para atualizar sua sessão.
Comments
Post a Comment