Tuesday, 6 March 2018

Processo readtoend waitforexit


ProcessStartInfo висит на & quot; WaitForExit & quot ;? Зачем?
У меня есть следующий код:
Я знаю, что результат процесса, который я запускаю, составляет около 7 МБ. Запуск его в консоли Windows отлично работает. К сожалению, программно это бесконечно зависает em WaitForExit. Обратите внимание, что это также делает код НЕ зависает для меньших выходов (например, 3 КБ).
Возможно ли, что внутренний StandardOutput em ProcessStartInfo не может буферизовать 7MB? Если да, то что мне делать вместо этого? Если нет, что я делаю неправильно?
17 ответов.
Проблема в том, что если вы перенаправляете StandardOutput и / или StandardError, внутренний буфер может стать полным. Какой бы порядок вы ни использовали, может возникнуть проблема:
Если вы дождались завершения процесса перед чтением StandardOutput, процесс может блокировать попытку записи на него, поэтому процесс не заканчивается. Если вы читаете из StandardOutput с помощью ReadToEnd, тогда ваш процесс может блокироваться, если процесс никогда не закрывается StandardOutput (например, если он никогда не завершается или блокируется при записи на StandardError).
Решение заключается в использовании асинхронных чтений, чтобы гарантировать, что буфер не будет заполнен. Чтобы избежать каких-либо взаимоблокировок и собрать весь вывод из StandardOutput и StandardError, вы можете сделать это:
EDITAR: см. ответы ниже о том, как избежать ObjectDisposedException, если произойдет таймаут.
документация для Process. StandardOutput говорит, чтобы прочитать, прежде чем ждать, иначе вы можете зайти в тупик, сниппет скопирован ниже:
Ответ Desde Mark Byers превосходный, но я бы просто добавил следующее: делегаты OutputDataReceived и ErrorDataReceived необходимо удалить до того, как будут удалены функции outputWaitHandle и errorWaitHandle. Если процесс продолжает выводить данные после того, как таймаут был превышен, а затем завершен, к ним будут доступны выходные переменные outputWaitHandle и errorWaitHandle после того, как они будут удалены.
(М м м м э э э э э э э и и и и и и и и
Проблема с необработанным объектом ObjectDisposedException возникает, когда процесс истекает. В этом случае другие части условия:
не выполняются. Я решил эту проблему следующим образом:
Роб ответил и спас мне несколько часов испытаний. Прочитайте буфер вывода / ошибки перед ожиданием:
У нас есть эта проблема (или вариант).
1) Добавьте тайм-атт в p. WaitForExit (nnnn); где nnnn находится в миллисекундах.
2) Поместите вызов ReadToEnd перед вызовом WaitForExit. Это то, что мы видели в MS.
Это более современное, решение для параллельной библиотеки задач (TPL) для 4.5 и выше.
Пример использования.
Реализация.
Я попытался создать класс, который бы разрешил вашу проблему, используя чтение асинхронного потока, принимая во внимание ответы Марка Байерса, Роба, stevejay. Сделав это, я понял, что есть ошибка, связанная с чтением выходного потока асинхронного процесса.
Você está interessado em:
Você está no System. InvalidOperationException: StandardOut имеет не был перенаправлен или процесс еще не начался.
Затем вам нужно запустить асинхронный вывод после того, как процесс начало:
Сделав это, сделайте условие гонки, потому что выходной поток может принимать перед установкой асинхронности:
Тогда некоторые люди могли сказать, что вам просто нужно прочитать поток прежде чем вы установите его асинхронным. Но та же проблема возникает. Там будет состоянием гонки между синхронным чтением и установкой поток в асинхронный режим.
Невозможно обеспечить безопасное асинхронное чтение выходного потока процесса на самом деле "Процесс" и "ProcessStartInfo" были разработаны.
Вероятно, вам лучше использовать асинхронное чтение, как это было предложено другими пользователями для вашего дела. Но вы должны знать, что вы можете пропустить некоторую информацию из-за состояния гонки.
Я решил это так:
Я перенаправил как входные, так и выходные данные, а также обработал чтение с потоков вывода и ошибок. Это решение работает для SDK 7-8, как для Windows 7, так и для para Windows 8.
Ни один из вышеперечисленных ответов не выполняет эту работу.
Por favor, Rob Robo, um "Mark Byers" получает исключение. (Я попробовал "решения" других ответов).
Поэтому я решил предложить другое решение:
Этот код отлаживается и работает отлично.
Мне кажется, что это простой и лучший подход (нам не нужно AutoResetEvent):
У меня была такая же проблема, но причина была другая. Однако это произойдет в Windows 8, но не под Windows 7. Кажется, что эта строка вызвала эту проблему.
Решением было НЕ отключить UseShellExecute. Теперь я получил всплывающее окно Shell, которое нежелательно, но намного лучше, чем программа, ожидающая ничего особенного. Поэтому я добавил для этого следующее:
Теперь меня беспокоит только то, почему это происходит в Windows 8.
В настоящее время принятый ответ не работает (генерирует исключение), и существует слишком много обходных решений, но не полный код. Это, очевидно, тратит много времени людям, потому что это популярный вопрос.
Объединив ответ Марка Байера и Кароль Тил, я написал полный код, основанный на том, как я хочу использовать метод Process. Start.
Использование.
Я использовал его для создания диалога прогресса вокруг команд git. Вот как я его использовал:
В теории вы также можете комбинировать stdout и stderr, но я не тестировал это.
Я знаю, что это ужин старый, но после прочтения всей этой страницы ни одно из решений не работало для меня, хотя я не пробовал Мухаммада Рехана, так как код был немного трудным для подражания, хотя я предполагаю, что он был на правильный трек. Когда я говорю, что это не сработало, что это не совсем так, иногда это будет работать нормально, я думаю, что это связано с длиной вывода до отметки EOF.
В любом случае, решение, которое работало для меня, состояло в том, чтобы использовать разные потоки для чтения StandardOutput и StandardError и писать сообщения.
Надеюсь, это поможет кому-то, кто думал, что это может быть так сложно!
Другие решения (в том числе EM0) все еще зашли в тупик для моего приложения из-за внутренних тайм-аутов и использования как стандартного, так и стандартногоError для созданного приложения. Вот что сработало для меня:
Изменить: добавлена ​​инициализация StartInfo для образца кода.
Это сообщение может быть устаревшим, но я узнал основную причину, по которой он обычно зависает, из-за для redirectStandardoutput или если у вас есть redirectStandarderror.
Поскольку выходные данные или данные об ошибках велики, это вызовет время зависания, поскольку оно все еще обрабатывается на неопределенный срок.

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.

Processo readtoend waitforexit
Obter através da App Store Leia esta publicação em nosso aplicativo!
StandardOutput. ReadToEnd () trava [duplicado]
Esta questão já tem uma resposta aqui:
Eu tenho um programa que freqüentemente usa um programa externo e lê suas saídas. Isso funciona muito bem, usando seu processo usual de redirecionamento de saída, mas um argumento específico, por algum motivo, trava quando eu tento lê-lo, nenhuma mensagem de erro - nenhuma exceção, apenas "pára" quando ele atinge essa linha. Naturalmente, eu uso uma função centralizada para chamar e ler a saída do programa, o que é o seguinte:
A linha que trava é resultado = proc. StandardOutput. ReadToEnd (); , mas novamente, não todas as vezes, somente quando enviado um argumento específico ("start-server"). Todos os outros argumentos funcionam bem - lê o valor e o retorna. Também é estranho o jeito que ele trava. Não congela ou comete um erro ou qualquer coisa, ele simplesmente pára o processamento. Como se fosse um comando de "retorno", exceto que ele nem sequer retorna à função de chamada, ele simplesmente pára tudo com a interface ainda está funcionando. Alguém experimentou isso antes? Alguém tem alguma ideia do que eu deveria tentar? Estou assumindo que é algo inesperado dentro do fluxo em si, mas existe uma maneira de lidar / ignorar isso para que ele lê de qualquer maneira?
marcado como duplicado por Peter Duniho c # Usuários com o crachá c # podem fechar as perguntas de c # como duplicatas e reabri-las conforme necessário. 27 de junho às 17h45.
Esta pergunta foi feita antes e já tem uma resposta. Se essas respostas não respondem totalmente a sua pergunta, faça uma nova pergunta.
As soluções propostas com BeginOutputReadLine () são uma boa maneira, mas em situações como essa, não é aplicável, porque o processo (certamente com o uso de WaitForExit ()) sai antes da saída assíncrona concluída completamente.
Então, tentei implementá-lo de forma síncrona e descobriu que a solução é usar o método Peek () da classe StreamReader. Eu adicionei check for Peek () & gt; -1 com certeza que não é o fim do fluxo como no artigo MSDN descrito e, finalmente, funciona e pára de pendurar!
Aqui está o código:
O problema é que você está usando os métodos síncronos ReadToEnd nos fluxos StandardOutput e StandardError. Isso pode levar a um potencial bloqueio que você está enfrentando. Isto é mesmo descrito no MSDN. A solução está descrita lá. Basicamente, é: use a versão assíncrona BeginOutputReadLine para ler os dados do fluxo StandardOutput:
E quanto a algo como:
Eu tive o mesmo problema de impasse. Este trecho de código funcionou para mim.
Eu tive o mesmo tipo de problema que o erro estava pendurado.
Com base na sua resposta a Daniel Hilgarth, nem tentei usar esses códigos, embora eu pense que eles teriam funcionado para mim.
Uma vez que eu quero ser capaz de fazer alguma saída mais fantástica ainda, eu decidi que eu faria isso com as duas saídas sendo feitas em uma linha de fundo.
Isso funcionou para mim e me permitiu não ter que usar um tempo limite para a leitura.
Algo que é elegante e trabalhou para mim é:
Esta resposta eu encontrei aqui e o truque está usando Flush () e Close () na entrada padrão.
A solução da resposta aceita não funcionou para mim. Eu tive que usar tarefas para evitar o impasse:
Com uma função GetStreamOutput da seguinte maneira:
Apenas no caso de alguém se tropeçar com esta questão, enquanto estiver usando Windows Forms e TextBox (ou RichTextBox) para mostrar os erros e as saídas, o processo retorna em tempo real (como eles são escritos para process. StandardOutput / process. StandardError).
Você precisa usar OutputDataReceived () / ErrorDataReceived () para ler ambos os fluxos sem deadlocks, não há maneira (tanto quanto eu sei) para evitar deadlocks de outra forma, mesmo a resposta de Fedor, que agora contém a tag "Answer" e o A maioria gosta de atualizar, não faz o truque para mim.
No entanto, quando você usa o RichTextBox (ou TextBox) para enviar os dados, outro problema que você encontra é como realmente gravar os dados na caixa de texto em tempo real (uma vez que ele chega). Você recebe o acesso aos dados dentro de um dos segmentos de fundo OutputDataReceived () / ErrorDataReceived () e você só pode anexar o texto () do thread principal.
O que eu tentei pela primeira vez era chamar processo. Iniciar () de uma linha de fundo e, em seguida, chamar BeginInvoke () = & gt; AppendText () nos segmentos OutputDataReceived () / ErrorDataReceived () enquanto o thread principal era process. WaitForExit ().
No entanto, isso levou a minha forma a congelar e finalmente pendurar por toda a eternidade. Depois de alguns dias de tentativa, acabei com a solução abaixo, que parece funcionar muito bem.
Em breve, você precisa adicionar as mensagens em uma coleção concorrente dentro dos segmentos OutputDataReceived () / ErrorDataReceived () enquanto o segmento principal deve tentar constantemente extrair as mensagens dessa coleção e anexá-las na caixa de texto:

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 meu aplicativo 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 postar uma descrição mais detalhada e uma amostra de código como um problema em https: // 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.

Первичная навигация.
Форум только для чтения.
Администраторы сделали этот форум доступным только для чтения. Новые беседы или комментарии не могут быть добавлены.
Processe hnags ao executar qualquer comando usando o & # 160; Process. Start ()
Porque se o Process. Start () for bem-sucedido, eu poderia começar a interrogar a saída.
O ManagementBaseObject retornado pelo InvokeMethod não contém o retorno de saída real pelo processo.
Eu acho que isso pode estar relacionado com o redirecionamento de saída / erro. Isso é feito de maneira sinônimo, então você não pode redirecionar os dois ao mesmo tempo. Para fazer isso, ele deve ser feito de forma assíncrona. (BeginOutputReadLine, BeginErrorReadLine)
& quot; 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 infantil esperaria indefinidamente para o pai ler o 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 segmentos e lendo a saída de cada fluxo em um segmento separado. & Quot;
URL em VS2005 Documentação:
Você já descobriu esse problema? Estou inclinado a pensar que é um bug no material de personificação em 2.0. Se eu remover a representação, isso funciona bem. mesmo a re-direção da saída e erro. Mas no momento que você tenta executar o processo como outro usuário, o processo é iniciado, mas depois trava. Eu diria segurança, exceto que não existe um erro por si. O processo começa bem, mas depois trava. Se fosse segurança, pensaria que você nunca começaria o processo. Também é interessante porque o problema também entra em cascata através dos processos. Por exemplo, eu tentei envolver minha chamada de personificação em outro exe para que eu pudesse iniciar o programa inicial (do ASP) sem nenhuma representação. A mesma coisa acontece; o processo trava. não o processo de invólucro. O processo dentro do invólucro que está sendo representado trava! Louco. Se você executar o wrapper exe como qualquer usuário, ele também funciona bem, então eu sei que o wrapper funciona em todos os contextos que não sejam asp.
Alguém encontrou a solução para este problema?
Aqui está um que funciona no modo de depuração no ASP (2.xxx),
mas não funciona no modo publicado: ajuda!
classe pública myClass.
string público strBalance = string. Empty;
string privado runProc (string args)
Process proc = new Process ();
string passwordPre = & quot; MyPassword & quot ;;
char [] passwordChars = passwordPre. ToCharArray ();
SecureString password = new SecureString ();
foreach (char c in passwordChars)
return strBalance; // Eu nunca chego aqui publicado, eu trabalho em depuração.
strBalance & # 43; = e. Data; // Eu nunca chegar aqui em publicado, eu trabalho em depuração.
Беседа заблокирована.
Администраторы заблокировали эту беседу. Новые комментарии не могут быть добавлены.
© Майкрософт (Microsoft), 2018. Корпорация Microsoft сохраняет за собой все права, связанные с материалами на этом сайте.

No comments:

Post a Comment