Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步读取进程输出时的延迟_C#_.net_Asynchronous_Process - Fatal编程技术网

C# 异步读取进程输出时的延迟

C# 异步读取进程输出时的延迟,c#,.net,asynchronous,process,C#,.net,Asynchronous,Process,我使用.NET和C#启动进程并异步读取其输出。我的问题是,在我的程序读取输出之前,似乎有一个延迟。如果我在命令行上运行可执行文件,当它开始运行时会立即有输出。但是,当我使用代码运行它时,在进程退出之前,不会调用ReadOutput事件处理程序。我想用它来提供进程输出的实时视图,所以我不想等待(几分钟)直到进程退出 以下是一些相关代码: MyProcess = new Process(); MyProcess.StartInfo.FileName = command; MyProcess.Star

我使用.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();
}
根据我使用lambda语法的评论,这是我做这件事的方式(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;
        }
//
///从启动的程序中收集标准输出文本。
/// 
私有静态只读StringBuilder outputText=new StringBuilder();
/// 
///从启动的程序中收集标准错误文本。
/// 
私有静态只读StringBuilder errorText=new StringBuilder();
/// 
///程序的入口点。
/// 
///命令行参数。
///退出代码。
私有静态int Main(字符串[]args)
{
使用(var process=process.Start)(新的ProcessStartInfo(
“program.exe”,
args)
{
CreateNoWindow=true,
ErrorDialog=false,
RedirectStandardError=true,
重定向标准输出=真,
UseShellExecute=false
}))
{
process.OutputDataReceived+=(发送流程、大纲)=>
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());
返回进程.ExitCode;
}
尝试添加方法调用:

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

// will wait for the associated process to exit
MyProcess.WaitForExit();

您的方法中的问题可能是流程只有在退出时才完成一行的输出。无法控制异步事件处理程序何时启动

在控制台应用程序中,最好定期检查新输出,并同步读取和显示:

        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);
            }
        }
在UI项目中,您将分别对WinForms和WPF使用
定时器
分派器
,以调用循环的内容并更新UI


请注意,我不会刷新
Console.Out
,因为
Console.Write()
Console.WriteLine()
会自动导致这种情况。

您使用相同的方法来处理OutputData和ErrorData的异步事件。我不会这样设计它。特别是因为
OutputBuilder
成员(我想是一个
StringBuilder
)正在从两个线程进行不安全的访问。我会将其分为两个方法,并将每个方法记录到一个单独的
StringBuilder
实例。这里的答案似乎都不能解决问题。我遇到了一个完全相同的问题,即进程早就结束了,但流仍在以某种方式写入。更新:我添加了一个循环延迟。我在某个地方读到200毫秒是有意识地注册一个事件所需的平均时间,因此这应该是低CPU使用率和流畅输出之间的一个很好的折衷。似乎
StandardOutput.EndOfStream
有时会挂起,直到流关闭。我尝试了@Tamschi和我的程序中建议的更改ram开始挂起。当我使用调试器连接到进程时,它显示它挂起在
EndOfStream
属性上。另一篇帖子()指示此属性可能会挂起,但我不明白原因。是否有人知道此属性挂起的原因或有其他想法?MSDN文档解释了上述StandardOutput代码可能导致死锁,进程将无限期等待StandardOutput流关闭。