【问题标题】:What are buffer sizes of Process.Start for stdout and stderr?标准输出和标准错误的 Process.Start 的缓冲区大小是多少?
【发布时间】:2017-04-04 20:06:03
【问题描述】:

我正在尝试找出这些信息。 显然,Microsoft 没有提供代码来可靠地读取进程 stdoutstderr 而不会出现死锁、异常和其他问题。

死锁问题

http://www.codeducky.org/process-handling-net/

一个不太明显的问题是死锁问题。所有三个流程流(输入、输出和错误)在它们可以缓冲多少内容方面都是有限的。如果内部缓冲区填满,那么写入流的任何人都会阻塞。例如,在这段代码中,直到进程退出后,我们才从 out 和 error 流中读取数据。这意味着我们可能会发现自己处于外部进程耗尽其错误缓冲区的情况。在这种情况下,外部进程将阻止写入标准错误,而我们的 .NET 应用程序被阻止读取到标准输出的末尾。因此,我们发现自己陷入了僵局!


网上没有可靠的代码

有 265 次赞成的答案,但我不会使用它,因为它受到 ObjectDisposeException 的影响并且需要超时:
ProcessStartInfo hanging on "WaitForExit"? Why?

在发现它可能导致ObjectDisposeException之前,它可能已被投票。


发生死锁的可能性有多大?

我想知道陷入僵局的可能性有多大。 为此,我需要知道 Windows 7 下 stderr 和 stdout 的缓冲区大小。

如何找到它们? 我以为我可以对几个文件进行分类,以查看大约文件大小会导致问题,但是在 Windows 7 下没有 cat。我什至尝试使用 git cat-file,但它的文档很差,没有使用示例,也没有人回答有关那:https://stackoverflow.com/questions/43203902/how-to-git-cat-file-a-file-in-current-dir

【问题讨论】:

  • 您提到的第一篇文章解释了如何避免死锁(从两个流中异步读取)。另外,还有type 命令,与cat 大体相似。
  • @Evk - 这是在我链接到的答案中完成的,但它会导致 ObjectDisposeException 并且需要超时,这在编写 git 包装器代码时并不方便(想想拉和推哪个访问互联网) .
  • 这些缓冲区存在于您启动的进程中,不在 .NET 中,也不在 Process 类中。实际大小完全取决于用于构建程序的工具链,4096 字节是一个非常典型的值。但是程序员可以改变它, setvbuf() 是用于这样做的样板 C 库函数。如果你想指责,那么你必须将矛头指向 Ken Thompson,I/O 重定向是一个非常糟糕的功能,本应保留在 Unix 中。
  • 答案中的代码确实被破坏了,但它是可以修复的,并且在另一个答案中有修复。此外,它与第一篇链接文章中提到的代码不同。我建议您尝试第一篇文章中看起来合理的代码,或者甚至尝试他们在那里建议的库(MediallionShell)。

标签: c#


【解决方案1】:

John 在他的评论中是正确的,它被硬编码为 4096 字节。

https://github.com/Microsoft/referencesource/blob/master/System/services/monitoring/system/diagnosticts/Process.cs

    if (startInfo.RedirectStandardInput) {
            standardInput = new StreamWriter(new FileStream(standardInputWritePipeHandle, FileAccess.Write, 4096, false), Console.InputEncoding, 4096);
            standardInput.AutoFlush = true;
        }
        if (startInfo.RedirectStandardOutput) {
            Encoding enc = (startInfo.StandardOutputEncoding != null) ? startInfo.StandardOutputEncoding : Console.OutputEncoding;
            standardOutput = new StreamReader(new FileStream(standardOutputReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096);
        }
        if (startInfo.RedirectStandardError) {
            Encoding enc = (startInfo.StandardErrorEncoding != null) ? startInfo.StandardErrorEncoding : Console.OutputEncoding;
            standardError = new StreamReader(new FileStream(standardErrorReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096);

}

我已经通过运行cmd.exe type path\to\file.html 命令对此进行了测试,但它打印的输出减少了,所以我编写了一个单行 ruby​​ 脚本来打开一个文件并将其打印到标准输出。它使用 4373 字节文件失败并使用 3007 字节文件。它只是挂起,死锁。

来自 Microsoft IMO 的真正可悲的流程处理。

【讨论】:

    猜你喜欢
    • 2018-12-12
    • 2012-06-09
    • 2013-11-28
    • 1970-01-01
    • 2011-01-05
    • 1970-01-01
    • 2022-07-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多