【问题标题】:Process takes longer to finish than in CMD完成过程比在 CMD 中花费的时间更长
【发布时间】:2014-05-03 12:22:38
【问题描述】:

我正在运行一个程序,该程序运行 driverquery.exe 命令并取回输出

        pProcess.StartInfo.CreateNoWindow = true;
        debugLog.WriteToLog("");
        pProcess.StartInfo.UseShellExecute = false;
        pProcess.StartInfo.RedirectStandardOutput = true;
        pProcess.StartInfo.WindowStyle =  System.Diagnostics.ProcessWindowStyle.Hidden;
        debugLog.WriteToLog("before start method");
        pProcess.Start();
        debugLog.WriteToLog("after start method");
        if (windowTitleToHide.Length > 0)
        {
            WindowsUtil.HideWindow(windowTitleToHide);
        }
        if (null != attributeName && !"".Equals(attributeName))
            Console.WriteLine(attributeName + " : ");
        debugLog.WriteToLog("before read to end");

        StreamReader reader = pProcess.StandardOutput;
        String strOutput = string.Empty;

        while (reader.Peek() > -1)
            strOutput += reader.ReadLine();

        debugLog.WriteToLog("after read to end");
        Console.WriteLine(strOutput);
        debugLog.WriteToLog("before wait for exit");
        pProcess.WaitForExit();
        debugLog.WriteToLog("after wait for exit");
        pProcess.Close();

该过程大约需要 30 分钟才能完成。如果我通过 cmd 运行相同的进程,它总是在 2 分钟内完成。我曾尝试使用 readtoend 而不是 readline 但这也没有帮助。有人能说出这里出了什么问题吗?在我的日志中,我可以看到最后一行打印为 before wait for exit

PS:当我看到任务管理器中的进程时,driverquery.exe 正在运行但不消耗任何 CPU 周期。调用此代码的进程消耗了大约 99% 的 CPU。我确定调用代码在运行此代码时没有执行任何其他任务。

【问题讨论】:

  • 查看是否向 StandardError 抛出错误。您可以从重新启用窗口开始,而不是重定向 StandardOutput 以查看它是否正在等待输入或为您提供一些其他诊断信息。
  • 您是否将一些参数传递给 driverquery.exe?
  • 不,我没有将任何参数传递给 driverquery。
  • 请不要在问题标题中包含有关所用语言的信息,除非没有它就没有意义。标记用于此目的。

标签: c# process readline


【解决方案1】:

我可能猜到这个问题与:

while (reader.Peek() > -1)
    strOutput += reader.ReadLine();

您可能没有阅读应用程序的完整输出。如果在其输出中有任何暂停,那么reader.Peek() 在应用程序完成其全部输出之前返回 -1。如果它输出大量数据,您甚至可能溢出输出流,因为您的进程在清空流一次后将放弃读取。如果是这种情况,子进程可能会生成大量异常输出到完整流(这将显着增加执行时间)。分析和调试会告诉您更多关于实际情况的信息。

您可以尝试这样的异步方法:

pProcess.StartInfo.RedirectStandardOutput = true;
pProcess.EnableRaisingEvents = true;  // Enable events
pProcess.OutputDataReceived += outputRedirection; // hook up
pProcess.Start();
pProcess.BeginOutputReadLine();  // use async BeginOutputReadLine
pProcess.WaitForExit();

在哪里

static void outputRedirection(object sendingProcess, 
                              DataReceivedEventArgs outLine)
{
    try
    {
        if (outLine.Data != null)
            Console.WriteLine(outLine.Data);
            // or collect the data, etc
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        return;
    }
}

而不是在一个紧密的循环中轮询(这可能会比子进程填充它更快地清空输出流,因此会失败),而是等待数据进入。您的主进程仍然会阻塞调用到WaitForExit,但线程池线程将处理传入事件。

编辑

这是一个很好用的SSCCE

    static void Main(string[] args)
    {            
        Stopwatch spw = new Stopwatch();
        spw.Start();
        Process pProcess = new Process();
        pProcess.StartInfo.FileName = "driverquery.exe";
        pProcess.StartInfo.CreateNoWindow = true;
        pProcess.StartInfo.UseShellExecute = false;
        pProcess.StartInfo.RedirectStandardOutput = true;
        pProcess.EnableRaisingEvents = true;
        pProcess.OutputDataReceived += outputRedirection;
        pProcess.Start();
        pProcess.BeginOutputReadLine();
        pProcess.WaitForExit();        
        pProcess.Close();
        spw.Stop();
        Console.WriteLine();
        Console.WriteLine("Completed in : " + 
                           spw.ElapsedMilliseconds.ToString() 
                           + "ms");
    }

使用上面定义的outputRedirection --> 输出:

如果这不适合您,请向我们展示您完整的真实代码。您正在做的其他事情是错误的。

【讨论】:

  • 非常好的解决方案!迫不及待想知道这是否能解决问题。
  • @J : 没有帮助..在 waitForExit() 行之后进程仍在等待..还有其他建议吗?
  • @ayush 那么你没有在你的代码中向我们展示一些东西。我附上了一个可以正常工作的 SSCCE。
  • 原来问题出在调用方法上..那个家伙也在运行一个不确定的线程并调用此代码...但是建议的答案是一个非常好的答案!它肯定会在以后帮助一些人。谢谢J...
猜你喜欢
  • 1970-01-01
  • 2019-08-24
  • 2019-11-22
  • 2012-02-18
  • 2014-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-01
相关资源
最近更新 更多