Beginnend synchron einen Prozess, und „Streaming“ die Ausgabe
-
28-09-2019 - |
Frage
Ich betrachte versuchen, einen Prozess von F # zu starten, warten, bis es fertig ist, sondern auch zunehmend sein Ausgang lesen.
Ist das der richtige / beste Weg, es zu tun? (In meinem Fall ich versuche git Befehle auszuführen, aber das ist tangential zur Frage)
let gitexecute (logger:string->unit) cmd =
let procStartInfo = new ProcessStartInfo(@"C:\Program Files\Git\bin\git.exe", cmd)
// Redirect to the Process.StandardOutput StreamReader.
procStartInfo.RedirectStandardOutput <- true
procStartInfo.UseShellExecute <- false;
// Do not create the black window.
procStartInfo.CreateNoWindow <- true;
// Create a process, assign its ProcessStartInfo and start it
let proc = new Process();
proc.StartInfo <- procStartInfo;
proc.Start() |> ignore
// Get the output into a string
while not proc.StandardOutput.EndOfStream do
proc.StandardOutput.ReadLine() |> logger
Was ich nicht verstehe, ist, wie die proc.Start () eine boolean zurückgeben kann und auch asynchron genug für mich sein, um die Ausgabe zu erhalten, aus dem während progressiv.
Leider habe ich momentan keine ausreichend große Repository haben - oder langsam genug Maschine, in der Lage sein zu sagen, was um Dinge geschehen in ...
UPDATE
Ich habe versucht, Brian Vorschlag, und es funktioniert.
Meine Frage war ein bisschen vage. Mein Missverständnis war, dass ich davon aus, dass Process.Start (), um den Erfolg des Prozesses als Ganzes zurückkehrte, und nicht nur der ‚Start‘, und so konnte ich nicht sehen, wie es könnte Arbeit.
Lösung
Der Code, den Sie in der Form geschrieben Sie schrieb es ist (fast) ok: Process.Start den Prozess starten Sie angeben, in, na ja, ein anderer Prozess, so dass Ihr Ausgangsstrom mit der Prozessausführung parallel passiert, liest. Ein Problem ist aber, dass Sie in einem Aufruf an process.WaitForExit am Ende werfen sollen -. Die Tatsache, dass Ausgangsstrom geschlossen ist, bedeutet nicht, dass Prozess beendet
Jedoch Sie Probleme mit synchronyous Lesung laufen wird, wenn Sie versuchen, Fehler- und Standardausgaben des Prozesses zu lesen: Es gibt keine Möglichkeit, 2-Streams synchron zu lesen und gleichzeitig - Sie werden Deadlocks, wenn Sie stdout lesen und verarbeiten zu stderr schreibt und wartet, bis Sie seinen Ausgang oder umgekehrt zu konsumieren.
Um dies zu vermitteln, die Sie OutputDataRecieved und ErrorDataRecieved abonnieren können, wie folgt aus:
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() }
Sie können auch Schreib etwas entlang der Linien von:
async {
while true do
let! args = Async.AwaitEvent p.OutputDataReceived
...
} |> Async.StartImmediate
für F # -Stil reaktive Ereignisbehandlung.