Starting a process synchronously, and “streaming” the output

前端 未结 1 1013
感情败类
感情败类 2021-01-02 02:21

I\'m looking at trying to start a process from F#, wait till it\'s finished, but also read it\'s output progressively.

Is this the right/best way to do it? (In m

相关标签:
1条回答
  • 2021-01-02 03:18

    The code you wrote in the form you wrote it is (almost) ok: process.Start start the process you specify in, well, another process, so your output stream reads will happen in parallel with your process execution. One issue though is that you should throw in a call to process.WaitForExit in the end - the fact that output stream is closed does not imply that process terminated.

    However you will run into problems with synchronyous reading if you try to read both stdout and stderr of the process: there is no way of reading 2 streams synchronously and simultaneously - you will deadlock if you read stdout and process is writing to stderr and waits for you to consume its output or vice versa.

    To mediate this, you can subscribe to OutputDataRecieved and ErrorDataRecieved, like this:

    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() }
    

    You can also write something along the lines of:

    async {
        while true do
            let! args = Async.AwaitEvent p.OutputDataReceived
            ...
    } |> Async.StartImmediate
    

    for F#-style reactive event handling.

    0 讨论(0)
提交回复
热议问题