파이썬 프로세스 1을 만들고 상호 작용하는 C# 응용 프로그램을 설정하는 데 문제가 있습니다. 간단한 예제가 아래에 나와 있습니다.Process의 빈 stdout에서 동기화 된 읽기 데이터로 인해 교착 상태가 발생합니다.
편집 : SO에 대한 추가 연구는 제 질문이 가능한 복제본임을 공개했습니다. 잠재적으로 .NET Framework의 알려진 버그는 here 및 here입니다. 2014 년에 유일한 쉬운 해결 방법은 실제로 자식 프로세스에 stdOut과 stdErr 모두에 무언가를 쓰도록 요청하는 것입니다. 그러나이 가정이 맞는지 2014 년 이후에 수정이 없었는지 궁금합니다.
나는 다음과 같은 경계 조건을 충족해야합니다 :
- 내가 스크립트 나 명령을 넘겨 후 파이썬 프로세스를 종료 할 수없는,하지만 난 살아 과정을 계속해야합니다. 편집 : 그 이유는 Process.WaitForExit() 메서드를 사용할 수 없다는 것입니다.
- std는 항상 열려 있기 때문에 EndOfStream을 확인할 수 없다고 생각합니다. 존재하지 않는 스트림의 끝.
- 또한 내 응용 프로그램은 파이썬 프로세스의 응답을 기다려야하므로 BeginOutputReadLine()을 OnOutputDataReceived와 함께 사용하는 비동기 옵션이 나에게 적절하지 않은 것 같습니다. 파이썬 전송 될 명령으로서 는 파이이 결과, 임의의 사용자 입력 수도있을 어느 표준 출력에 저장된 "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()은 잘린 줄과 관련된 문제를보고하지 못하게합니다.
프로세스가 계속 실행되어야하므로 Process.WaitForExit()을 사용할 수 없습니다 (초기 게시물의 조건 1 참조). 그리고 파이썬 프로세스가 콘솔 윈도우를 보여주지 않아서, Process.WaitForInputIdle() 메소드가 나에게 적절하지 않은 것처럼 보입니다. 나는 그에 따라 초기 게시물을 편집했다. – Bechi