处理大型数据流标准输出重定向时WaitForExit挂起的问题
通过ProcessStartInfo
执行进程时,可能会遇到与StandardOutput
缓冲区限制相关的问题。具体来说,当重定向StandardOutput
时,如果输出大小超过某个阈值(例如7MB),程序可能会在WaitForExit
期间无限期挂起。
原因
当重定向StandardOutput
且内部缓冲区已满时,就会发生此行为。如果调用进程在读取StandardOutput
之前等待目标进程退出,则目标进程在尝试写入已满的缓冲区时会被阻塞,从而阻止其结束。相反,如果调用进程使用ReadToEnd
检索输出,则如果目标进程不关闭StandardOutput
(例如,如果它不终止或其StandardError
流被阻塞),它可能会被阻塞。
解决方案
为了解决这个问题,请使用异步读取以防止缓冲区达到容量。以下代码示例演示了如何执行此操作:
<code class="language-csharp">using (Process process = new Process()) { process.StartInfo.FileName = filename; process.StartInfo.Arguments = arguments; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; StringBuilder output = new StringBuilder(); StringBuilder error = new StringBuilder(); using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false)) using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false)) { process.OutputDataReceived += (sender, e) => { if (e.Data == null) { outputWaitHandle.Set(); } else { output.AppendLine(e.Data); } }; process.ErrorDataReceived += (sender, e) => { if (e.Data == null) { errorWaitHandle.Set(); } else { error.AppendLine(e.Data); } }; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); if (process.WaitForExit(timeout) && outputWaitHandle.WaitOne(timeout) && errorWaitHandle.WaitOne(timeout)) { // 进程已完成。在此处检查 process.ExitCode。 } else { // 超时。 } } }</code>
此解决方案使用异步回调来处理从StandardOutput
和StandardError
接收到的数据,确保内部缓冲区不会满并防止死锁。
注意:为了避免在发生超时时出现ObjectDisposedException
,请在访问进程的输出或错误流之前检查进程的HasExited
属性。
以上是为什么WaitForexit失速使用大型数据流将标准输出重定向时?的详细内容。更多信息请关注PHP中文网其他相关文章!