2016-07-18 8 views
0

1のpythonプロセスを作成して操作するC#アプリケーションの設定に問題があります。簡単な例を以下に示します。プロセスの空のstdoutから同期データが読み込まれるとデッドロックが発生する

EDIT: SOに関するさらなる調査で、私の質問は重複している可能性があることが明らかになりました。潜在的に関連する.NET Frameworkの既知のバグはherehereです。 2014年の唯一の簡単な回避策は、子プロセスにstdOutとstdErrの両方に何かを書くように依頼することです。しかし、私はこの仮説が正しいかどうかを知りたいと思っています.2014年以降の修正がないかどうか疑問に思っていますか?

私は次の境界条件を満たさなければならない:

  1. 私は、スクリプトまたはコマンドを引き渡した後のpythonのプロセスを閉じることができませんが、私は生きているプロセスを維持する必要があります。 編集:そのため、Process.WaitForExit()メソッドを使用することはできません。
  2. stdは常に開いたままであるため、EndOfStreamを確認することはできません。ストリームの終わり、それは存在しません。
  3. さらに、私のアプリケーションはPythonプロセスの応答を待たなければならないので、BeginOutputReadLine()を使ってOnOutputDataReceivedを使った非同期オプションは私にとっては適切ではないようです。
  4. Pythonに送信されるコマンドは任意のユーザー入力であるため、pythonsの結果はstdOutまたはstdErr( "4 + 7"はstdOutに "11"が格納され、 "4 + a"は "name" 「私は何をすべきかSTDERRに)

された:対話モードでのpythonのプロセスを設定

  • (引数 " '' 定義されていません-i")
  • STDINのリダイレクトを有効にします、Out、およびErr
  • プロセスを開始する
  • はその後、STDの

ためStreamReadersとライターを取得し、私は当初、stdoutとstderrを確認したいです。 Pythonはstderrに情報の以下の部分を書き込む私がを知っ

のPython 2.7.11(v2.7.11:6d1b6a68f775、2015年12月5日、午後08時32分19秒)[MSC v.1500

をWin32で32ビット(インテル)]と私はerrorReader.Peek()を使用してerrorReader 2から文字ベースを読み取ることによって、この行を取得することができています。

ただし、別のプロセスの状況はまったく異なる場合があります。 Pythonを使用しても、私は次の問題に遭遇します。最初にoutputReaderから読み込みたい場合、その中には何も含まれず、outputReader.Peek()はデッドロックになるようです。前述のように、outputReader.EndOfStreamまたはoutputReader.ReadToEnd()も同じです。だから、どのように私はstdOut デッドロックを引き起こすことなくまったく使用できるかどうかを知ることができますか?

はコード:

 // 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 ...ニシキヘビ応答は2^N + 1バイト長であるとき、多分私はバッファの問題に実行する、将来がもたらすものを知っています。しかし、Peek()は、切り捨てられた行に関連する問題を報告するのを防ぎます。

答えて

0

あなたが終了してからバッファを読み取るためのプロセスを待つことができた場合は、Process.WaitForExitを使用することができるかもしれません。また、Process.WaitForInputIdleを確認する方法もありますが、実行時にPythonスクリプトが取得するとは思わないメッセージループを持つプロセスに依存します。

+0

プロセスを実行し続ける必要があるため、Process.WaitForExit()を使用することはできません(最初の投稿の条件1を参照)。また、Pythonプロセスはコンソールウィンドウを表示しないので、Process.WaitForInputIdle()メソッドも私にとっては適切ではないようです。私はそれに応じて最初の投稿を編集した – Bechi

関連する問題