如何以有效的方式从子进程'stdout中读取长行?

时间:2013-09-10 10:00:25

标签: c# .net visual-studio-2010 stdout child-process

注意:自第一个版本以来,此问题已发生重大变化,因此有些评论或答案可能看起来很奇怪。如果看起来很奇怪,请检查编辑历史记录。

我正在从C#类库启动子进程。

我正在使用Process.BeginOutputReadLine()以异步方式读取输出/错误。我认为它不适用于非常长的行,但问题似乎是它不可扩展。在我的电脑中,一条128 kb线路立即被处理,512 kb线路似乎需要大约1分钟,1 mb似乎需要几分钟,而我已经等了两个小时等待10 mb线路进行处理,并且当我取消它时,它仍在工作。

直接从StandardOutput和StandardError流修复读取似乎很容易,但来​​自这些流的数据似乎是缓冲的。如果我从stdout获取数据以填充缓冲区,然后从stderr获取更多数据,我找不到检查其中一个数据是否有待处理的方法,如果我尝试从stderr读取,它将挂起永远。 为什么会发生这种情况,我做错了什么,以及正确的做法是什么?

一些代码示例用于说明我正在尝试实现的目标。

Program1

    // Writes a lot of data to stdout and stderr
    static void Main(string[] args)
    {
        int numChars = 512 * 1024;
        StringBuilder sb = new StringBuilder(numChars);

        String s = "1234567890";

        for (int i = 0; i < numChars; i++)
            sb.Append(s[i % 10]);

        int len = sb.Length;
        Console.WriteLine(sb.ToString());
        Console.Error.WriteLine(sb.ToString());
    }

Program2

    // Calls Program1 and tries to read its output.
    static void Main(string[] args)
    {
       StringBuilder sb = new StringBuilder();
       StringBuilder sbErr = new StringBuilder();

       proc.StartInfo.CreateNoWindow = true;
       proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
       proc.StartInfo.UseShellExecute = false;

       proc.StartInfo.RedirectStandardError = true;
       proc.StartInfo.RedirectStandardOutput = true;
       proc.StartInfo.RedirectStandardInput = false;

       proc.StartInfo.Arguments = "";
       proc.StartInfo.FileName = "program1.exe";

       proc.ErrorDataReceived += (s, ee) => { if (ee.Data != null) sbErr.AppendLine(ee.Data); };
       proc.OutputDataReceived += (s, ee) => { if (ee.Data != null) sb.AppendLine(ee.Data); };

       proc.Start();
       proc.BeginOutputReadLine();
       proc.BeginErrorReadLine();
       proc.WaitForExit();
    }

Program1有一个常量,允许设置要生成的数据大小,Program2启动Program1并尝试读取数据。我应该期待时间与大小呈线性增长,但似乎比这更糟糕。

1 个答案:

答案 0 :(得分:0)

我希望我理解你的问题。该应用程序挂起Process.WaitForExit(),因为这是Process.WaitForExit()it waits for the process to exit

您可能想在新线程中调用它: int创建进程的方法:

    Thread trd = new Thread(new ParameterizedThreadStart(Start));
     trd.Start();

并添加此方法:

  private void Start(object o)
  {
     ((Process)o).WaitForExit();
     // your code after process ended
  }