Thursday 19 April 2018

Processo readtoend waitforexit


o registro de walter.
. Escrevendo enquanto aprende.
Sexta-feira, 18 de novembro de 2018.
Process. WaitForExit (Int32) bloqueia o problema.
Como você pode ver, o código inicia um processo "cmd. exe" e passa para ele o comando que eu quero ser executado.
No código eu usei o comando ping - t 8.8.8.8 que, por causa da opção - t, pings o host sem parar. O que acontece? O processo "cmd. exe" juntamente com o comando ping - t nunca sai e nunca fecha o fluxo de stdout e, portanto, o nosso código trava no Output = process. StandardOutput. ReadToEnd (); linha, porque não pode ter sucesso em ler todo o fluxo.
O mesmo acontece também se um comando em um arquivo em lotes trava por qualquer motivo e, portanto, o código acima pode funcionar continuamente por anos e, em seguida, pendure de repente sem nenhum motivo aparente.
você pode enfrentar um impasse se o comando que você atribui a "cmd. exe" ou o processo que você está chamando preenche a saída padrão ou erro padrão. Isso porque nosso código não pode alcançar as linhas.
Na verdade, o processo filho (o comando ping ou um arquivo em lote ou o processo que estiver executando) não pode continuar se o nosso programa não ler os buffers preenchidos dos fluxos e isso não pode acontecer porque o código está pendurado na linha com o processo. WaitForExit () que aguardará para sempre que o projeto filho saia.
O tamanho padrão de ambos os fluxos é de 4096 bytes. Você pode testar esses dois tamanhos com esses arquivos em lote:

Processo readtoend waitforexit
Obter através da App Store Leia esta publicação em nosso aplicativo!
ReadToEnd da saída de processo std e waitforexit.
Do exemplo do MSDN de usar stdoutput do processo recém-criado:
Se, em vez de myStreamReader. ReadLine (), estou usando myStreamReader. ReadToEnd () devo continuar usando myProcess. WaitForExit ()? Ou ReadToEnd () aguardará até que o processo seja concluído?
EDIT: Desculpe pelo desvio, para responder diretamente a sua pergunta. Sim, você precisa chamar Process. WaitForExit (); . Isso garantirá que o processo tenha produzido toda a sua saída antes de chamar ReadToEnd ()
ReadToEnd é função síncrona. Portanto, se você não o chamar em seu código, ele bloqueará seu segmento principal até que ele capture apenas o primeiro resultado do StandardOutput, então é isso. Mas usando WaitForExit irá garantir que você tenha tudo.
Além disso, você pode considerar fazer uma leitura assíncrona da saída do processo, veja este Exemplo MSDN que implementa OutputDataRecieved.
"ReadToEnd" é uma função armazenada no objeto "StreamReader" e não acho que tenha algo a ver com a espera de um processo para sair, no entanto, a classe "Processo" pode lidar com isso. Por sinal, todas as habilidades "StreamReader" não são úteis na situação que você mencionou.
No meu ponto de vista, "WaitForExit" deve ser chamado e, como você fez "Fechar" também. Porque eles vão divulgar alguns recursos do sistema que nenhum outro método pode. Tanto quanto eu sei, o método "ReadToEnd" não tem nada a ver com chamar esses dois.

Honey Mercy.
Apenas outro site do WordPress.
[] Solução: WaitForExit NÃO é executado após Process. Start ()
WaitForExit NÃO é executado após Process. Start () é chamado.
Quando um Processo grava texto em seu fluxo padrão, esse texto normalmente é exibido no console. Ao redirecionar o fluxo StandardOutput, você pode manipular ou suprimir a saída de um processo. Por exemplo, você pode filtrar o texto, formatá-lo de forma diferente ou escrever a saída para o console e um arquivo de log designado.
O fluxo de saída StandardOutput redirecionado pode ser lido de forma síncrona ou assíncrona. Métodos como Read, ReadLine e ReadToEnd executam operações de leitura síncrona no fluxo de saída do processo. Essas operações de leitura síncrona não são concluídas até que o Processo associado escreva seu fluxo StandardOutput ou encerre o fluxo.
Em contraste, BeginOutputReadLine inicia operações de leitura assíncronas no fluxo StandardOutput. Este método habilita um manipulador de eventos designado para a saída do fluxo e retorna imediatamente ao chamador, o que pode executar outro trabalho enquanto a saída do fluxo é direcionada para o manipulador de eventos.
As operações de leitura síncrona introduzem uma dependência entre a leitura do chamador do fluxo StandardOutput e a escrita do processo filho para esse fluxo. Essas dependências podem resultar em condições de impasse. Quando o chamador lê do fluxo redirecionado de um processo filho, depende da criança. O chamador aguarda a operação de leitura até que a criança grava a transmissão ou encerre o fluxo. Quando o processo filho grava dados suficientes para preencher o fluxo redirecionado, ele depende do pai. O processo filho aguarda a próxima operação de gravação até que o pai lê do fluxo completo ou fecha o fluxo. A condição de deadlock resulta quando o processo do chamador e filho aguardam um para o outro para concluir uma operação, e nenhum deles pode prosseguir. Você pode evitar deadlocks avaliando as dependências entre o chamador eo processo filho.
O seguinte código C #, por exemplo, mostra como ler de um fluxo redirecionado e aguarde o processo filho sair.
O exemplo de código evita uma condição de bloqueio chamando p. StandardOutput. ReadToEnd antes de p. WaitForExit. Uma condição de impasse pode resultar se o processo pai chama p. WaitForExit antes de p. StandardOutput. ReadToEnd eo processo filho grava texto suficiente para preencher o fluxo redirecionado. O processo pai aguardaria indefinidamente o processo filho para sair. O processo filho esperaria indefinidamente para o pai ler do fluxo de StandardOutput completo.
Há um problema semelhante ao ler todo o texto da saída padrão e dos fluxos de erro padrão. O código C # a seguir, por exemplo, executa uma operação de leitura em ambos os fluxos.
O exemplo de código evita a condição de bloqueio executando operações de leitura assíncronas no fluxo StandardOutput. Um estado de impasse resulta se o processo pai chamar p. StandardOutput. ReadToEnd seguido de p. StandardError. ReadToEnd e o processo filho escreve texto suficiente para preencher o fluxo de erros. O processo pai aguardaria indefinidamente o processo filho para fechar o fluxo StandardOutput. O processo filho esperaria indefinidamente para o pai ler do fluxo completo do StandardError.
Você pode usar operações de leitura assíncronas para evitar essas dependências e seu potencial de impasse. Alternativamente, você pode evitar a condição de bloqueio criando dois tópicos e lendo a saída de cada fluxo em um segmento separado.
Relacionados.
Pós-navegação.
Deixe uma resposta Cancelar resposta.
O que é para todos os corpos, é o meu primeiro a ver esse blog; Esta página contém dados incríveis e verdadeiramente excelentes em apoio aos visitantes.

Exemplo de uso.
Resolvi assim:
Eu redirecionava a entrada, a saída e o erro e administrai a leitura dos fluxos de saída e erro. Esta solução funciona para o SDK 7- 8.1, tanto para o Windows 7 como para o Windows 8.
Eu tentei fazer uma aula que resolva seu problema usando a leitura de fluxo assíncrono, levando em conta Mark Byers, Rob, Stevejay responde. Ao fazê-lo, percebi que existe um erro relacionado à leitura assíncrona do fluxo de saída do processo.
Você não pode fazer isso:
Você receberá System. InvalidOperationException: StandardOut não foi redirecionado ou o processo ainda não começou.
Então, você deve iniciar a saída assíncrona lida após o processo ser iniciado:
Fazendo isso, faça uma condição de corrida porque o fluxo de saída pode receber dados antes de configurá-lo como assíncrono:
Então algumas pessoas podem dizer que você só precisa ler o fluxo antes de configurá-lo como assíncrono. Mas o mesmo problema ocorre. Haverá uma condição de corrida entre a leitura síncrona e configurará o fluxo em modo assíncrono.
Não há como conseguir uma leitura assíncrona segura de um fluxo de saída de um processo na forma real "Processo" e "ProcessStartInfo" foi projetado.
Você provavelmente está melhor usando a leitura assíncrona, como sugerido por outros usuários para o seu caso. Mas você deve estar ciente de que você pode perder algumas informações devido à condição de corrida.
Nenhuma das respostas acima está fazendo o trabalho.
A solução Rob trava e a solução 'Mark Byers' obtém a exceção descarta. (Eu tentei as "soluções" das outras respostas).
Então eu decidi sugerir outra solução:
Este código é depurado e funciona perfeitamente.
Eu acho que isso é uma abordagem simples e melhor (não precisamos do AutoResetEvent):
Eu estava tendo o mesmo problema, mas a razão era diferente. No entanto, isso aconteceria no Windows 8, mas não no Windows 7. A seguinte linha parece ter causado o problema.
A solução era NÃO desativar UseShellExecute. Agora recebi uma janela popup do Shell, que é indesejável, mas muito melhor do que o programa esperando que nada de particular aconteça. Então eu adicionei o seguinte trabalho para isso:
Agora, o único problema que me incomoda é o porquê isso está acontecendo no Windows 8, em primeiro lugar.
Introdução.
A resposta atualmente aceita não funciona (lança exceção) e há muitas soluções alternativas, mas nenhum código completo. Isso é, obviamente, desperdiçando muito tempo das pessoas porque esta é uma questão popular.
Combinando a resposta de Mark Byers e a resposta de Karol Tyl, escrevi um código completo baseado em como eu quero usar o método Process. Start.
Eu usei-o para criar um diálogo de progresso em torno dos comandos git. É assim que eu usei isso:
Em teoria, você também pode combinar stdout e stderr, mas não testei isso.
Eu sei que isso é velho, mas, depois de ler toda essa página, nenhuma das soluções estava funcionando para mim, embora eu não tentei Muhammad Rehan porque o código era um pouco difícil de seguir, embora eu acho que ele estava no caminho certo . Quando eu digo que não funcionou, isso não é inteiramente verdade, às vezes funcionaria bem, acho que é algo a ver com a duração da saída antes de uma marca EOF.
De qualquer forma, a solução que funcionou para mim era usar diferentes threads para ler o StandardOutput e StandardError e escrever as mensagens.
Espero que isso ajude alguém, que pensou que isso poderia ser tão difícil!
As outras soluções (incluindo o EM0) ainda estão bloqueadas para o meu aplicativo, devido a tempos de espera internos e ao uso de StandardOutput e StandardError pela aplicação gerada. Aqui está o que funcionou para mim:
Editar: inicialização adicionada de StartInfo para codificar a amostra.
Este post talvez esteja desactualizado, mas descobri a principal causa por que normalmente ele trava é devido ao excesso de pilha para o redirectStandardoutput ou se você tem redirectStandarderror.
Como os dados de saída ou os dados de erro são grandes, isso causará um tempo de espera, pois ele ainda está processando por tempo indefinido.

Code Ducky.
um blog para codificadores por codificadores.
Trabalhando com processos em.
Os idiomas de scripts e shell são geralmente construídos em torno da capacidade de um processo para iniciar facilmente e trabalhar com os resultados dos outros. Este é o principal modo de processamento em bash, enquanto o ruby ​​suporta pelo menos 5 abordagens integradas com diferentes níveis de flexibilidade e concisão.
Em, isso é uma espécie de operação normalmente é feito através da API System. Diagnostics. Process. O Process API é bastante geral e poderoso, mas pode ser complicado e difícil de usar corretamente nos casos de uso comum que são tratados tão bem pelas linguagens acima. Como um spoiler, acabei envolvendo grande parte dessa complexidade em uma nova biblioteca: MedallionShell. Com o MedallionShell, esse tipo de tarefa é um one-liner:
Mais sobre isso mais tarde, no entanto. Por enquanto, vamos voltar ao Processo. Como um exemplo concreto, recentemente queria que minha aplicação lancasse uma instância do NodeJS para executar o compilador menos css. Eu precisava escrever na entrada padrão do Node & # 8217; ao capturar o texto de saída padrão, texto de erro padrão e código de saída.
Uma tentativa inicial.
Aqui é o código com que comecei:
Este código é bastante detalhado; infelizmente também é bastante buggy.
Lidando com os argumentos do processo.
Um dos primeiros problemas que notamos com este código é que a propriedade Arguments no ProcessStartInfo é apenas uma string. Se os argumentos que estamos passando são dinâmicos, precisaremos fornecer a lógica de escape adequada antes de concatenar para impedir que coisas como espaços em caminhos de arquivos sejam quebrados. Escapar os argumentos da linha de comando do Windows é estranhamente complexo; Felizmente, o código necessário para implementá-lo está bem documentado nesta publicação do StackOverflow. Assim, a primeira mudança que nós vamos fazer é adicionar lógica de escape:
Lidar com deadlocks.
Um problema menos óbvio é o bloqueio. Os três fluxos de processo (entrada, saída e erro) são finitos em quanto de conteúdo eles podem armazenar. Se o buffer interno for preenchido, então quem estiver escrevendo para o fluxo irá bloquear. Neste código, por exemplo, não lemos os fluxos de saída e erro até que o processo tenha saído. Isso significa que podemos encontrar-nos em um caso em que o Node esgota o buffer de erro. Nesse caso, o Nó bloquearia a gravação em erro padrão, enquanto nosso aplicativo está bloqueado a leitura até o final do padrão. Assim, nós nos encontramos em um impasse!
O Process API fornece um método que parece projetado para lidar com isso: BeginOutput / ErrorReadLine. Com este método, você pode assinar o assíncrono & # 8220; DataReceived & # 8221; eventos em vez de ler os fluxos de saída diretamente. Dessa forma, você pode ouvir ambos os fluxos ao mesmo tempo. Infelizmente, este método não fornece nenhuma maneira de saber quando o último bit de dados foi recebido. Porque tudo é assíncrono, é possível (e eu observei isso) para que os eventos disparem depois que WaitForExit () retornou.
Felizmente, podemos fornecer nossa própria solução alternativa usando Tarefas para ler asíncronamente as transmissões enquanto aguardamos o Nó para sair:
Adicionando um tempo limite.
Outra questão que gostaria de lidar é a de um processo pendurado. Em vez de esperar para que o processo saia, nosso código seria mais robusto se forçássemos um timeout em vez disso:
Async todo o caminho!
Enquanto nós agora estamos usando o IO assíncrono para ler dos fluxos do processo, ainda estamos bloqueando um segmento enquanto aguardamos o processo para concluir. Podemos melhorar a eficiência aqui, indo totalmente assíncrono:
Adaptando-se a volumes de dados maiores.
Outra questão que pode surgir ao tentar generalizar essa abordagem é a do volume de dados. Se estivermos fornecendo uma grande quantidade de dados através do processo, nós provavelmente queremos substituir as chamadas convenientes ReadToEndAsync () com loops de leitura assíncronos que processam cada pedaço de dados conforme ele vem.
Mudando para MedallionShell.
Nós já construímos um código (esperançosamente) correto, robusto e eficiente para trabalhar com um processo. No entanto, espero que este exemplo o tenha convencido de que a API do Processo não é suficiente para o trabalho quando se trata de facilidade de uso. Para esse fim, irei apresentar uma alternativa: a biblioteca MedallionShell (disponível no NuGet). Aqui, a lógica equivalente usando MedallionShell:
Com o MedallionShell, os argumentos são escapados automaticamente, os fluxos de processo são automaticamente armazenados em buffer para evitar o impasse, e tudo está bem envolvido em uma API baseada em tarefas compatível com asínc. Nós não teremos que nos preocupar em chamar Dispose (): por padrão, o Processo é descartado automaticamente após a conclusão do comando.
O MedallionShell também oferece sobrecargas do operador para permitir o redirecionamento semelhante à da entrada padrão e saída padrão. Isso significa que você pode usar & # 8220; & lt; & # 8221; e & # 8220;> & # 8221; para canalizar dados de e para fluxos, arquivos e coleções. Você pode até usar o & # 8220; | & # 8221; para canalizar dados de um objeto Command para outro.
Mike Adelson.
Últimas publicações de Mike Adelson (ver todos)
Implementando Equals () e GetHashCode () em C # 7 - 3 de junho de 2017 Scripting in C # - 3 de maio de 2017 7 maneiras de usar C # 7 throw expressions - 26 de abril de 2017.
Sobre Mike Adelson.
I & # 8217; m engenheiro de software em Applied Predictive Technologies em Washington D. C., onde trabalho em & # 8220; dados grandes & # 8221; análise e desenvolvimento web. No meu tempo livre, eu gosto de ler, trabalhar em vários projetos paralelos e responder perguntas no StackOverflow.
Pós-navegação.
7 pensamentos sobre & ldquo; Trabalhando com processos em & rdquo;
É possível ler e escrever para o mesmo processo dentro do mesmo programa. Eu usei o shell medalhão para ler a saída de um programa de console interativo. Mas quando eu iniciar um segmento diferente para escrever comandos para o programa, o writestream. writeline parece apenas pendurar. Estou tentando controlar pianobar (veja github). Há algum passo ao tentar ler uma linha do processo e responder com uma linha. Isto está me enlouquecendo.
Sim, deve ser possível ler e escrever para um processo dentro do mesmo programa. Certifique-se de que está usando a versão mais recente do MedallionShell e que a entrada padrão do comando está definida como AutoFlush (deve ser o padrão).
Você pode observar WriteLine para pendurar se o processo de destino não for puxar os dados e o buffer interprocesso for preenchido (evitando assim que o preenchimento seja concluído).
É difícil para mim dizer mais sem ver o seu código; considere publicar uma descrição mais detalhada e uma amostra de código como um problema no github / madelson / MedallionShell.
Obrigado Michael. Eu fiz exatamente isso, o problema # 9 #. Liguei a minha pergunta. Claramente, eu estava com muito sono para escrever qualquer coisa. Eu quis dizer que há algum passo que é necessário que eu esteja faltando. Algo óbvio para todos os outros por mim.
É possível aguardar uma string específica no fluxo de saída do comando?
bool found = await cmd. StandardOutput. Expect (searchstring, timeout);
Não há funcionalidades incorporadas para fazer isso. Se a string não abranger uma linha, você poderia fazer:
enquanto ((linha = cmd. StandardOutput. ReadLine ())! = null)
Se a cadeia de pesquisa abranger várias linhas, você pode usar uma técnica de loop semelhante, onde você acompanha os últimos N caracteres onde N é o comprimento da seqüência de pesquisa.

No comments:

Post a Comment