2011-03-03 102 views
2

我正在使用.NET和C#啓動進程並異步讀取它的輸出。我的問題是,在我的程序讀取輸出之前似乎有延遲。如果我在命令行上運行可執行文件,它會在開始運行時立即輸出。但是當我使用我的代碼運行它時,ReadOutput事件處理程序不會在Process退出之前調用。我想用它來提供進程輸出的實時視圖,所以我不想等待(幾分鐘),直到進程退出。異步讀取進程輸出時的延遲

下面是一些相關的代碼:

MyProcess = new Process(); 
MyProcess.StartInfo.FileName = command; 
MyProcess.StartInfo.Arguments = args; 
MyProcess.StartInfo.UseShellExecute = false; 
MyProcess.StartInfo.RedirectStandardOutput = true; 
MyProcess.StartInfo.RedirectStandardError = true; 
MyProcess.StartInfo.RedirectStandardInput = true; 
MyProcess.OutputDataReceived += new DataReceivedEventHandler(ReadOutput); 
MyProcess.ErrorDataReceived += new DataReceivedEventHandler(ReadOutput); 

if (!MyProcess.Start()) 
{ 
    throw new Exception("Process could not be started"); 
} 

try 
{ 
    MyProcess.BeginOutputReadLine(); 
    MyProcess.BeginErrorReadLine(); 
} 
catch (Exception ex) 
{ 
    throw new Exception("Unable to begin asynchronous reading from process"; 
} 

這是我的事件處理程序:

private void ReadOutput(object sendingProcess, DataReceivedEventArgs outLine) 
{ 
    OutputBuilder.AppendLine(outLine.Data); 
    Console.WriteLine(outLine.Data); 
    Console.Out.Flush(); 
} 
+2

您正在使用相同的方法處理OutputData和ErrorData的異步事件。我不會這樣設計它。特別是因爲'OutputBuilder'成員(一個'StringBuilder',我假設?)正在被兩個線程不安全地訪問。我將它分成兩個方法,每個方法都記錄到一個單獨的'StringBuilder'實例。 – 2011-03-03 22:59:07

+0

這裏沒有任何答案似乎解決了這個問題。我在這個過程早已過去的時候遇到了完全相同的問題,但這些流仍然以某種方式寫入。 – OSH 2014-08-13 14:23:51

回答

3

這是我做的方式(C#3)按使用lambda語法我的意見。

/// <summary> 
    /// Collects standard output text from the launched program. 
    /// </summary> 
    private static readonly StringBuilder outputText = new StringBuilder(); 

    /// <summary> 
    /// Collects standard error text from the launched program. 
    /// </summary> 
    private static readonly StringBuilder errorText = new StringBuilder(); 

    /// <summary> 
    /// The program's entry point. 
    /// </summary> 
    /// <param name="args">The command-line arguments.</param> 
    /// <returns>The exit code.</returns> 
    private static int Main(string[] args) 
    { 
     using (var process = Process.Start(new ProcessStartInfo(
      "program.exe", 
      args) 
      { 
       CreateNoWindow = true, 
       ErrorDialog = false, 
       RedirectStandardError = true, 
       RedirectStandardOutput = true, 
       UseShellExecute = false 
      })) 
     { 
      process.OutputDataReceived += (sendingProcess, outLine) => 
       outputText.AppendLine(outLine.Data); 

      process.ErrorDataReceived += (sendingProcess, errorLine) => 
       errorText.AppendLine(errorLine.Data); 

      process.BeginOutputReadLine(); 
      process.BeginErrorReadLine(); 
      process.WaitForExit(); 
      Console.WriteLine(errorText.ToString()); 
      Console.WriteLine(outputText.ToString()); 
      return process.ExitCode; 
     } 
0

嘗試添加MyProcess.WaitForExit方法調用:

MyProcess.BeginOutputReadLine(); 
MyProcess.BeginErrorReadLine(); 

// will wait for the associated process to exit 
MyProcess.WaitForExit(); 
1

在你的方法這個問題可能是,它退出時的過程只完成一個線的產量。無法控制異步事件處理程序何時啓動。

在一個控制檯應用程序,最好的辦法是定期檢查是否有新的輸出和閱讀並同步顯示出來:

 while (!p.HasExited) 
     { 
      if (!p.StandardOutput.EndOfStream) 
      { 
       errorBuilder.Append(p.StandardError.ReadToEnd()); 
       outputBuilder.Append(p.StandardOutput.ReadToEnd()); 
       Console.Write(p.StandardOutput); 
      } 
      else 
      { 
       Thread.Sleep(200); 
      } 
     } 

在UI項目,你會使用TimerDispatcherTimer的WinForms和WPF,分別調用循環的內容並更新UI。

請注意,我不會沖洗Console.Out,因爲Console.Write()Console.WriteLine()會自動導致此問題。

+0

更新:我給循環添加了一個延遲。我在某處看到,200毫秒是有意識地註冊事件所需的平均時間,所以這應該是低CPU使用率和流暢輸出之間的良好折中。 – Tamschi 2011-03-04 15:23:12

+1

看起來'StandardOutput.EndOfStream'有時會掛起,直到流關閉。我嘗試了@Tamschi的建議更改,我的程序開始掛起。當我使用調試器連接到進程時,它顯示它掛在'EndOfStream'屬性上。另一篇文章([鏈接](http://stackoverflow.com/questions/2767496/standardoutput-endofstream-hangs))表明這個屬性可能會掛起,但我不明白爲什麼。有沒有人有一個想法,爲什麼這會掛起或有另一個想法? – Brian 2011-03-14 20:31:59

+1

MSDN文檔解釋了上面的StandardOutput代碼可能導致進程等待無限期地等待StandardOutput流關閉的死鎖。 https://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput(v=vs.110).aspx – 2016-09-28 14:25:21