Задержки при чтении вывода процесса асинхронно - PullRequest
2 голосов
/ 04 марта 2011

Я использую .NET и C # для запуска процесса и асинхронного чтения его результатов.Моя проблема в том, что кажется, что задержка перед тем, как вывод прочитан моей программой.Если я запускаю исполняемый файл в командной строке, сразу же начинается его запуск.Но когда я запускаю его, используя мой код, обработчик события ReadOutput не вызывается, пока не завершится процесс.Я хочу использовать это для предоставления в реальном времени представления о выходе процесса, поэтому я не хочу ждать (несколько минут), пока процесс не завершится.

Вот некоторый соответствующий код:

MyProcess = new Process();
MyProcess.StartInfo.FileName = command;
MyProcess.StartInfo.Arguments = args;
MyProcess.StartInfo.UseShellExecute = false;
MyProcess.StartInfo.RedirectStandardOutput = true;
MyProcess.StartInfo.RedirectStandardError = true;
MyProcess.StartInfo.RedirectStandardInput = true;
MyProcess.OutputDataReceived += new DataReceivedEventHandler(ReadOutput);
MyProcess.ErrorDataReceived += new DataReceivedEventHandler(ReadOutput);

if (!MyProcess.Start())
{
    throw new Exception("Process could not be started");
}

try
{
    MyProcess.BeginOutputReadLine();
    MyProcess.BeginErrorReadLine();
}
catch (Exception ex)
{
    throw new Exception("Unable to begin asynchronous reading from process";
}

А вот мой обработчик событий:

private void ReadOutput(object sendingProcess, DataReceivedEventArgs outLine)
{
    OutputBuilder.AppendLine(outLine.Data);
    Console.WriteLine(outLine.Data);
    Console.Out.Flush();
}

Ответы [ 3 ]

3 голосов
/ 04 марта 2011

Это то, как я это делаю (C # 3) согласно моему комментарию, используя лямбда-синтаксис.

    /// <summary>
    /// Collects standard output text from the launched program.
    /// </summary>
    private static readonly StringBuilder outputText = new StringBuilder();

    /// <summary>
    /// Collects standard error text from the launched program.
    /// </summary>
    private static readonly StringBuilder errorText = new StringBuilder();

    /// <summary>
    /// The program's entry point.
    /// </summary>
    /// <param name="args">The command-line arguments.</param>
    /// <returns>The exit code.</returns>
    private static int Main(string[] args)
    {
        using (var process = Process.Start(new ProcessStartInfo(
            "program.exe",
            args)
            {
                CreateNoWindow = true,
                ErrorDialog = false,
                RedirectStandardError = true,
                RedirectStandardOutput = true,
                UseShellExecute = false
            }))
        {
            process.OutputDataReceived += (sendingProcess, outLine) =>
                outputText.AppendLine(outLine.Data);

            process.ErrorDataReceived += (sendingProcess, errorLine) =>
                errorText.AppendLine(errorLine.Data);

            process.BeginOutputReadLine();
            process.BeginErrorReadLine();
            process.WaitForExit();
            Console.WriteLine(errorText.ToString());
            Console.WriteLine(outputText.ToString());
            return process.ExitCode;
        }
1 голос
/ 04 марта 2011

Проблема в вашем подходе, вероятно, заключается в том, что процесс завершает вывод строки только после ее выхода. Нет способа контролировать, когда запускаются асинхронные обработчики событий.

В консольном приложении лучше всего периодически проверять наличие нового вывода, читать и отображать его синхронно:

        while (!p.HasExited)
        {
            if (!p.StandardOutput.EndOfStream)
            {
                errorBuilder.Append(p.StandardError.ReadToEnd());
                outputBuilder.Append(p.StandardOutput.ReadToEnd());
                Console.Write(p.StandardOutput);
            }
            else
            {
                Thread.Sleep(200);
            }
        }

В проекте пользовательского интерфейса вы должны использовать Timer или DispatcherTimer для WinForms и WPF соответственно, чтобы вызывать содержимое цикла и обновлять пользовательский интерфейс.

Обратите внимание, что я не сбрасываю Console.Out, поскольку Console.Write() и Console.WriteLine() вызывают это автоматически.

0 голосов
/ 04 марта 2011

Попробуйте добавить MyProcess.WaitForExit вызов метода:

MyProcess.BeginOutputReadLine();
MyProcess.BeginErrorReadLine();

// will wait for the associated process to exit
MyProcess.WaitForExit();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...