问题描述
我期待在试图启动从F#一个过程,等到它的完成,同时也阅读它的输出逐渐。
I'm looking at trying to start a process from F#, wait till it's finished, but also read it's output progressively.
这是做正确的/最好的方法是什么? (在我的情况下,我试图执行git的命令,但相切的问题)的
Is this the right/best way to do it? (In my case I'm trying to execute git commands, but that is tangential to the question)
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.Start()可以返回一个布尔值,而且也有足够的异步的,我得到的输出出来的同时逐步
What I don't understand is how the proc.Start() can return a boolean and also be asynchronous enough for me to get the output out of the while progressively.
不幸的是,我目前还没有一个足够大的存储库 - 或减缓足够的机,能告诉什么样的顺序事情发生在...
Unfortunately, I don't currently have a large enough repository - or slow enough machine, to be able to tell what order things are happening in...
更新
我想布赖恩的建议,和它的工作。
I tried Brian's suggestion, and it does work.
我的问题是有点含糊。我的误解是,我假设的Process.Start()返回的过程中作为一个整体的成功,而不是仅仅的开始,因此我看不出它是如何的可以的工作。
My question was a bit vague. My misunderstanding was that I assumed that Process.Start() returned the success of the process as a whole, and not just of the 'Start', and thus I couldn't see how it could work.
推荐答案
您在你写的是(几乎)OK的形式写了code:的Process.Start启动您在指定进程,那么,另一个进程,所以你的输出流中读取数据将并行发生在你的流程执行。一个问题是,虽然你应该打电话丢给process.WaitForExit到底 - 事实上,输出流并不意味着这个过程结束封闭
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.
然而,你会碰到问题synchronyous阅读,如果你尝试读取标准输出和过程的标准错误:没有办法读2个数据流同步,同时 - 你会死锁如果你阅读标准输出和处理写入到标准错误并等待你消耗它的输出,反之亦然。
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.
为调解这一点,你可以订阅OutputDataRecieved和ErrorDataRecieved,像这样的:
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
有关F#风格的反应事件处理。
for F#-style reactive event handling.
这篇关于启动过程中同步进行,并与QUOT;流&QUOT;输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!