2016-07-18 16 views
0

파이썬 프로세스 1을 만들고 상호 작용하는 C# 응용 프로그램을 설정하는 데 문제가 있습니다. 간단한 예제가 아래에 나와 있습니다.Process의 빈 stdout에서 동기화 된 읽기 데이터로 인해 교착 상태가 발생합니다.

편집 : SO에 대한 추가 연구는 제 질문이 가능한 복제본임을 공개했습니다. 잠재적으로 .NET Framework의 알려진 버그는 herehere입니다. 2014 년에 유일한 쉬운 해결 방법은 실제로 자식 프로세스에 stdOut과 stdErr 모두에 무언가를 쓰도록 요청하는 것입니다. 그러나이 가정이 맞는지 2014 년 이후에 수정이 없었는지 궁금합니다.

나는 다음과 같은 경계 조건을 충족해야합니다 :

  1. 내가 스크립트 나 명령을 넘겨 후 파이썬 프로세스를 종료 할 수없는,하지만 난 살아 과정을 계속해야합니다. 편집 : 그 이유는 Process.WaitForExit() 메서드를 사용할 수 없다는 것입니다.
  2. std는 항상 열려 있기 때문에 EndOfStream을 확인할 수 없다고 생각합니다. 존재하지 않는 스트림의 끝.
  3. 또한 내 응용 프로그램은 파이썬 프로세스의 응답을 기다려야하므로 BeginOutputReadLine()을 OnOutputDataReceived와 함께 사용하는 비동기 옵션이 나에게 적절하지 않은 것 같습니다. 파이썬 전송 될 명령으로서
  4. 는 파이이 결과, 임의의 사용자 입력 수도있을 어느 표준 출력에 저장된 "11"에 표준 출력 또는 STDERR에서 ("4 + 7"결과, "이름"4 +는 "결과 'A'정의되지 않은 "에) STDERR에

내가 할 것은 :

  • 대화식 모드에서 파이썬 프로세스를 설정 (인수는"-i ")
  • 표준 입력의 리디렉션을 가능하게 , 출력 및 오류
  • 프로세스 시작
  • ,451,515,
  • 그 후 표준의

에 대한 StreamReaders와 작가, 나는 처음에 표준 출력과 표준 에러를 검사 할 수. 파이썬은 STDERR에 다음과 같은 정보 조각을 쓰는 내가을 알고

파이썬 2.7.11 (v2.7.11 : 6d1b6a68f775 12 월 (5) 2015 년 20시 32분 19초) [MSC v.1500 Win32에서

내가 errorReader.Peek를 사용하여이 줄을 얻을 수 있어요()와 읽기에 32 비트 (인텔)]를 errorReader 2에서 문자 기반.

그러나 다른 프로세스의 상황은 완전히 다를 수 있습니다. 파이썬으로도, 나는 다음과 같은 문제에 봉착한다 : outputReader에서 처음 읽으 려 할 때, 거기에 아무 것도없고 outputReader.Peek()가 교착 상태에 빠져있는 것 같다. 위에서 설명한 것처럼 outputReader.EndOfStream 또는 outputReader.ReadToEnd()도 마찬가지입니다. 그렇다면 어떻게 알 수 있습니까? 은 교착 상태를 일으키지 않고 전혀 사용할 수 있습니까?

코드 :

 // create the python process StartupInfo object 
     ProcessStartInfo _tempProcessStartInfo = new ProcessStartInfo(@"C:\TMP\Python27\python.exe"); 
     // ProcessStartInfo _tempProcessStartInfo = new ProcessStartInfo(PathToPython + "python.exe"); 

     // python uses "-i" to run in interactive mode 
     _tempProcessStartInfo.Arguments = "-i"; 

     // Only start the python process, but don't show a (console) window 
     _tempProcessStartInfo.WindowStyle = ProcessWindowStyle.Minimized; 
     _tempProcessStartInfo.CreateNoWindow = true; 


     // Enable the redirection of python process std's 
     _tempProcessStartInfo.UseShellExecute = false; 

     _tempProcessStartInfo.RedirectStandardOutput = true; 
     _tempProcessStartInfo.RedirectStandardInput = true; 
     _tempProcessStartInfo.RedirectStandardError = true; 

     // Create the python process object and apply the startupInfos from above 
     Process _tempProcess = new Process(); 
     _tempProcess.StartInfo = _tempProcessStartInfo; 

     // Start the process 
     bool _hasStarted = _tempProcess.Start(); 

     //// ASynch reading seems not appropriate to me: 
     // _tempProcess.BeginOutputReadLine(); 
     // _tempProcess.BeginErrorReadLine(); 

     // Create StreamReaders and Writers for the Std's 
     StreamReader outputReader = _tempProcess.StandardOutput; 
     StreamReader errorReader = _tempProcess.StandardError; 
     StreamWriter commandWriter = _tempProcess.StandardInput; 

     // Create StringBuilder that collects results and ErrorMessages 
     StringBuilder tmp = new StringBuilder(""); 

     // Create temp variable that is used to peek into streams. C# uses -1 to indicate that there is no more byte to read 
     int currentPeek = -1; 

     // Get Initial Error Message. In this specific case, this is the python version 
     tmp.AppendLine("INITIAL ERROR MESSAGE:"); 
     currentPeek = errorReader.Peek(); 
     while (currentPeek >= 0) 
     { 
      char text = (char)errorReader.Read(); 
      tmp.Append(text); 
      currentPeek = errorReader.Peek(); 
     } 

     // Get initial output Message. In this specific case, this is EMPTY, which seems to cause this problem, as ... 
     tmp.AppendLine("INITIAL STDOUT MESSAGE:"); 

     //// ... the following command CREATES a well defined output, and afterwards everything works fine (?) but ... 
     //commandWriter.WriteLine(@"print 'Hello World'"); 

     //// ... without the the above command, neither 
     //bool isEndOfStream = outputReader.EndOfStream; 
     //// ... nor 
     // currentPeek = outputReader.Peek(); 
     //// ... nor 
     // tmp.AppendLine(outputReader.ReadLine()); 
     //// ... nor 
     //tmp.AppendLine(outputReader.ReadToEnd()); 
     //// ... works 

     // Therefore, the following command creates a deadlock 
     currentPeek = outputReader.Peek(); 
     while (currentPeek >= 0) 
     { 

      char text = (char)outputReader.Read(); 
      tmp.Append(text); 
      currentPeek = errorReader.Peek(); 
     } 

     _currentPythonProcess = _tempProcess; 
     return true; 

1이 매우 구체적인 문제에 대한 쉬운 수정은 단순히 "4"는 "4"를 반환뿐만 아니라, 예를 들어, 첫 번째 프로세스에 유효한 명령을 전송하는 것입니다 .. 그러나 프로세스 스트림, 파이프 및 대응하는 독자와 작성자가 어떻게 작동하는지 그리고 C#에서이를 어떻게 사용할 수 있는지 알고 싶습니다. 누가 미래를 가져올 지, 누가 비단뱀 응답이 2^n + 1 바이트 길이가되면 버퍼 문제가 생길지 ... 2 나는 또한 줄 단위로 읽을 수 있다는 것을 알고있다. 그러나 Peek()은 잘린 줄과 관련된 문제를보고하지 못하게합니다.

답변

0

프로세스가 끝날 때까지 기다린 다음 버퍼를 읽을 수 있으면 Process.WaitForExit을 사용할 수 있습니다. 또한 확인할 수있는 또 다른 방법은 Process.WaitForInputIdle이지만 메시지 루프가있는 프로세스에 따라 다릅니다. 실행시 Python 스크립트가 실행되는 것으로 생각하지 않습니다.

+0

프로세스가 계속 실행되어야하므로 Process.WaitForExit()을 사용할 수 없습니다 (초기 게시물의 조건 1 참조). 그리고 파이썬 프로세스가 콘솔 윈도우를 보여주지 않아서, Process.WaitForInputIdle() 메소드가 나에게 적절하지 않은 것처럼 보입니다. 나는 그에 따라 초기 게시물을 편집했다. – Bechi