Я смотрю на попытку запустить процесс с F#, ожидать, пока это не закончено, но также и читайте, это прогрессивно производится.
Действительно ли это - право/лучший способ сделать это? (В моем случае я пытаюсь выполнить команды мерзавца, но это является тангенциальным к вопросу),
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
То, что я не понимаю, то, как proc. Запустите (), может возвратить булевскую переменную и также быть достаточно асинхронным, чтобы я получал вывод из в то время как прогрессивно.
К сожалению, я в настоящее время не имею достаточно большого репозитория - или замедляю достаточно машины, чтобы смочь сказать то, в чем происходят вещи порядка...
ОБНОВЛЕНИЕ
Я попробовал предложение Brian, и оно действительно работает.
Мой вопрос был немного неопределенен. Мое недоразумение состояло в том, что я принял тот Процесс. Запустите (), возвратил успех процесса в целом, и не только 'Запуска', и таким образом я не мог видеть, как он мог работать.
Код, который вы написали в том виде, в котором вы его написали, (почти) хорош: process.Start запускает процесс, который вы указали, в, ну, в другом процессе, так что чтение вашего выходного потока будет происходить параллельно с выполнением вашего процесса. Правда, есть одна проблема: в конце нужно бросить вызов process.WaitForExit - тот факт, что выходной поток закрыт, не означает, что процесс завершился.
Однако вы столкнетесь с проблемами синхронного чтения, если попытаетесь читать и stdout, и stderr процесса: не существует способа читать два потока синхронно и одновременно - вы попадете в тупик, если вы читаете stdout, а процесс пишет в stderr и ждет, пока вы потребите его вывод, или наоборот.
Чтобы смягчить эту ситуацию, вы можете подписаться на OutputDataRecieved и ErrorDataRecieved, например, так:
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
для реактивной обработки событий в стиле F#.