gpt4 book ai didi

.net - 如何避免以错误的顺序从 Process 类接收事件?

转载 作者:行者123 更新时间:2023-12-01 13:24:29 24 4
gpt4 key购买 nike

假设我想编写一个调用另一个程序的程序,该程序的输出同时包含 stdout 输出和 stderr 输出。

例如,我调用的这个程序是 F# 编译器试图编译包含错误的 F# 文件:

F# Compiler for F# 4.0 (Open Source Edition)
Freely distributed under the Apache 2.0 Open Source License

/builds/someLib.fs(27,42): error FS0001: Type mismatch. Expecting a
string * string
but given a
string * string * 'a
The tuples have differing lengths of 2 and 3

(前两行打印到stdout,其余的打印到stderr。)

所以我写了一个这样处理进程类的程序:

type OutChunk = StdOut of string | StdErr of string
type OutputBuffer = list<OutChunk>
type ProcessResult = { ExitCode: int; Output: OutputBuffer }

module Process =

let Execute (command: string, args: string, hidden: bool)
: ProcessResult =

// I know, this shit below is mutable, but it's a consequence of dealing with .NET's Process class' events
let outputBuffer = new System.Collections.Generic.List<OutChunk>()
let outputBufferLock = new Object()

use outWaitHandle = new AutoResetEvent(false)
use errWaitHandle = new AutoResetEvent(false)

let startInfo = new ProcessStartInfo(command, args)
startInfo.UseShellExecute <- false
startInfo.RedirectStandardOutput <- true
startInfo.RedirectStandardError <- true

use proc = new System.Diagnostics.Process()
proc.StartInfo <- startInfo

let outReceived (e: DataReceivedEventArgs): unit =
if (e.Data = null) then
outWaitHandle.Set() |> ignore
else
if not (hidden) then
Console.WriteLine(e.Data)
lock outputBufferLock (fun _ -> outputBuffer.Add(OutChunk.StdOut(e.Data)))

let errReceived (e: DataReceivedEventArgs): unit =
if (e.Data = null) then
errWaitHandle.Set() |> ignore
else
if not (hidden) then
Console.Error.WriteLine(e.Data)
lock outputBufferLock (fun _ -> outputBuffer.Add(OutChunk.StdErr(e.Data)))

proc.OutputDataReceived.Add outReceived
proc.ErrorDataReceived.Add errReceived

proc.Start() |> ignore
let exitCode =
try
proc.BeginOutputReadLine()
proc.BeginErrorReadLine()
proc.WaitForExit()
proc.ExitCode
finally
outWaitHandle.WaitOne() |> ignore
errWaitHandle.WaitOne() |> ignore
{ ExitCode = exitCode; Output = List.ofSeq(outputBuffer) }

let rec PrintToScreen (outputBuffer: OutputBuffer) =
match outputBuffer with
| [] -> ()
| head::tail ->
match head with
| StdOut(out) -> Console.WriteLine(out)
| StdErr(err) -> Console.Error.WriteLine(err)
PrintToScreen(tail)

但是,即使我在上面的代码中使用锁来防止在写入可变列表时出现竞争条件,有时当我运行调用 F# 编译器的 F# 程序时,然后调用 PrintToScreen 函数,我得到混合流:

F# Compiler for F# 4.0 (Open Source Edition)

/builds/someLib.fs(27,42): error FS0001: Type mismatch. Expecting a
Freely distributed under the Apache 2.0 Open Source License
string * string
but given a
string * string * 'a
The tuples have differing lengths of 2 and 3

(如您所见,许可证文本应该在编译器错误之前到达!但它没有)

这怎么可能?如何处理恶魔般的 System.Diagnostics.Process 类以正确的顺序接收流/事件?

最佳答案

这可能是输出缓冲的情况。您是否尝试过在写入 stdoutstderr< 后调用 Console.Out.Flush()Console.Error.Flush()/分别?

关于.net - 如何避免以错误的顺序从 Process 类接收事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40966435/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com