流程需要比CMD更长的时间才能完成

时间:2014-03-25 14:58:09

标签: c# process readline

我正在运行一个运行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,但这也没有帮助。有人能告诉我这里有什么问题吗?在我的日志中,我可以看到最后一行在等待退出之前打印为

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

1 个答案:

答案 0 :(得分:2)

我猜可能与问题有关:

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 - >输出:

enter image description here

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