Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.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
.net 同步启动流程,以及;“流媒体”;输出_.net_F#_Synchronous_Processstartinfo - Fatal编程技术网

.net 同步启动流程,以及;“流媒体”;输出

.net 同步启动流程,以及;“流媒体”;输出,.net,f#,synchronous,processstartinfo,.net,F#,Synchronous,Processstartinfo,我正在尝试从F#开始一个进程,等待它完成,但也要逐步读取它的输出 这是正确的/最好的方法吗?(在我的例子中,我试图执行git命令,但这与问题无关) 让gitexecute(记录器:字符串->单位)cmd= 让procStartInfo=newprocessstartinfo(@“C:\ProgramFiles\Git\bin\Git.exe”,cmd) //重定向到Process.StandardOutput StreamReader。 procStartInfo.RedirectStandar

我正在尝试从F#开始一个进程,等待它完成,但也要逐步读取它的输出

这是正确的/最好的方法吗?(在我的例子中,我试图执行git命令,但这与问题无关)

让gitexecute(记录器:字符串->单位)cmd=
让procStartInfo=newprocessstartinfo(@“C:\ProgramFiles\Git\bin\Git.exe”,cmd)
//重定向到Process.StandardOutput StreamReader。

procStartInfo.RedirectStandardOutput以您编写的形式编写的代码(几乎)是ok:process。启动您在另一个进程中指定的进程,这样您的输出流读取将与进程执行并行进行。但有一个问题是,最后应该调用process.WaitForExit——输出流关闭并不意味着进程终止

但是,如果您尝试同时读取进程的stdout和stderr,您将在同步读取时遇到问题:无法同时同步读取2个流-如果您读取stdout,而进程正在写入stderr,并等待您使用其输出,或者相反,您将死锁

要解决此问题,您可以订阅OutputDataReceived和ErrorDataReceived,如下所示:

type ProcessResult = { exitCode : int; stdout : string; stderr : string }

let executeProcess (exe,cmdline) =
    let psi = new System.Diagnostics.ProcessStartInfo(exe,cmdline) 
    psi.UseShellExecute <- false
    psi.RedirectStandardOutput <- true
    psi.RedirectStandardError <- true
    psi.CreateNoWindow <- true        
    let p = System.Diagnostics.Process.Start(psi) 
    let output = new System.Text.StringBuilder()
    let error = new System.Text.StringBuilder()
    p.OutputDataReceived.Add(fun args -> output.Append(args.Data) |> ignore)
    p.ErrorDataReceived.Add(fun args -> error.Append(args.Data) |> ignore)
    p.BeginErrorReadLine()
    p.BeginOutputReadLine()
    p.WaitForExit()
    { exitCode = p.ExitCode; stdout = output.ToString(); stderr = error.ToString() }

对于F#风格的反应式事件处理。

我在使用异步工作流处理此类任务方面取得了一些成功:我实际上不确定这里的问题是什么。上面的代码是否有效?问题是什么?在我看来,你可以编写tester.exe,它会将几行代码写入标准输出并刷新,等待两秒钟,再写入两行。。。然后用它来测试这段代码是否按照你的要求运行,是吗?@Brian,你说得对,我做了,它也做了。谢谢。@Stringer,有意思,谢谢你。+1回答了我没有问的其余问题:)你的代码中只有一个错误是这个进程。Start()不返回进程,它返回一个布尔值。我正在调用一个静态进程。Start(ProcessStartInfo)返回一个进程()此解决方案的问题是,事件
OutputDataReceived
ErrorDataReceived
仅在发送EOL后触发,因此可能会发生流程要求用户在同一行中回答某个问题(例如
您确定吗?[Y/N]
),然后F#流程包装器将不会打印该事件
type ProcessResult = { exitCode : int; stdout : string; stderr : string }

let executeProcess (exe,cmdline) =
    let psi = new System.Diagnostics.ProcessStartInfo(exe,cmdline) 
    psi.UseShellExecute <- false
    psi.RedirectStandardOutput <- true
    psi.RedirectStandardError <- true
    psi.CreateNoWindow <- true        
    let p = System.Diagnostics.Process.Start(psi) 
    let output = new System.Text.StringBuilder()
    let error = new System.Text.StringBuilder()
    p.OutputDataReceived.Add(fun args -> output.Append(args.Data) |> ignore)
    p.ErrorDataReceived.Add(fun args -> error.Append(args.Data) |> ignore)
    p.BeginErrorReadLine()
    p.BeginOutputReadLine()
    p.WaitForExit()
    { exitCode = p.ExitCode; stdout = output.ToString(); stderr = error.ToString() }
async {
    while true do
        let! args = Async.AwaitEvent p.OutputDataReceived
        ...
} |> Async.StartImmediate