C#のWPFアプリケーションから外部アプリケーションとしてPythonを呼び出したところ、動きはしたもののPython側でPrintしている標準出力がC#側で上手く受け取れず苦労したのでメモ。
現象としては、python側のPrint内容がリアルタイムでC#側に通知されず、pythonの実行が終了したタイミングで一気にまとめて通知されてしまうという感じ。
解決:オプション一つでサクサクになった
python側のPrint関数呼び出し時にflushオプションをTrueにするだけで解決した。
動作したソースコードを記載しておく。
まずはC#側から、こちらは至って普通。
// 外部アプリケーションを起動
private void StartProcess()
{
string option = "オプションパラメータ";
string python_path = "PyFile.py";
var task = Task.Run(() =>
{
var myProcess = new Process
{
StartInfo = new ProcessStartInfo("python.exe")
{
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
Arguments = python_path + " " + option
}
};
myProcess.EnableRaisingEvents = true;
myProcess.OutputDataReceived += new DataReceivedEventHandler(OnDataReceived);
myProcess.ErrorDataReceived += new DataReceivedEventHandler(OnErrorReceived);
myProcess.Start();
myProcess.BeginOutputReadLine();
myProcess.BeginErrorReadLine();
myProcess.WaitForExit();
myProcess.Close();
});
}
// イベントハンドラ 標準出力用
private void OnDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
Console.WriteLine(e.Data);
}
}
// イベントハンドラ エラーメッセージ用
private void OnErrorReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
Console.WriteLine(e.Data );
}
}
続いてpython側、print呼び出し時のflushオプションにTrueを渡すだけ。
def hoge():
print("hoge called.", flush=True)
return
とりあえずこれだけで調子良くPrint結果を受け取り始める。
おまけ
全部のprint文に手動でflush=True書くのがめんどい人へ。
私は元のpythonで大量にPrint文を呼び出していたので、以下の感じでPrint関数自体を上書きしました。参考までに。
print_origin = print // 元のPrintをとっておく
// Print関数をオーバーライド
def print(s):
print_origin(s, flush=True) // ここでオプションをつける
return
def hoge():
print("hoge called.") // オーバーライドした方を呼び出し
return