邮箱处理器和例外

qeh*_*hgt 15 f# mailboxprocessor

我想知道,为什么MailboxProcessor处理异常的默认策略只是默默地忽略它们.例如:

let counter =
    MailboxProcessor.Start(fun inbox ->
        let rec loop() =
            async { printfn "waiting for data..."
                    let! data = inbox.Receive()
                    failwith "fail" // simulate throwing of an exception
                    printfn "Got: %d" data
                    return! loop()
            }
        loop ())
()
counter.Post(42)
counter.Post(43)
counter.Post(44)
Async.Sleep 1000 |> Async.RunSynchronously
Run Code Online (Sandbox Code Playgroud)

没有任何反应.程序执行没有致命的停止,或者出现带有"未处理的异常"的消息框.没有.

如果有人使用PostAndReply方法,这种情况会变得更糟:结果是保证死锁.

这种行为有什么理由吗?

Bri*_*ian 13

ErrorMailboxProcessor上有一个事件.

http://msdn.microsoft.com/en-us/library/ee340481

counter.Error.Add(fun e -> printfn "%A" e)
Run Code Online (Sandbox Code Playgroud)

当然,如果你想自己施加精细控制,你可以做一些类似Tomas的解决方案.

  • 是的,我知道此成员“错误”。我不知道为什么错误处理程序上的默认设置什么都不做。它可以重新抛出,或写入stderr,或暂停应用程序-比静默地忽略异常要好得多。 (2认同)
  • h!我正在寻找标准`MailboxProcessor`上的现有事件,但是不知何故我完全错过了`Error`事件。 (2认同)

Tom*_*cek 5

我认为MailboxProcessorF#中不包含任何处理异常的机制的原因是不清楚这样做的最佳方法是什么.例如,您可能希望在发生未处理的异常时触发全局事件,但您可能希望在下次调用Post或时重新抛出异常PostAndReply.

这两个选项都可以基于标准实现MailboxProcessor,因此可以添加所需的行为.例如,以下代码段显示HandlingMailbox添加了一个全局异常处理程序.它具有与正常相同的接口MailboxProcessor(我省略了一些方法),但它添加了OnError在发生异常时触发的事件:

type HandlingMailbox<'T> private(f:HandlingMailbox<'T> -> Async<unit>) as self =
  let event = Event<_>()
  let inbox = new MailboxProcessor<_>(fun inbox -> async {
    try 
      return! f self
    with e ->
      event.Trigger(e) })
  member x.OnError = event.Publish
  member x.Start() = inbox.Start()
  member x.Receive() = inbox.Receive()
  member x.Post(v:'T) = inbox.Post(v)
  static member Start(f) =
    let mbox = new HandlingMailbox<_>(f)
    mbox.Start()
    mbox
Run Code Online (Sandbox Code Playgroud)

要使用它,您将编写与之前编写的代码相同的代码,但您现在可以异步处理异常:

let counter = HandlingMailbox<_>.Start(fun inbox -> async {
  while true do 
    printfn "waiting for data..." 
    let! data = inbox.Receive() 
    failwith "fail" })

counter.OnError.Add(printfn "Exception: %A")
counter.Post(42) 
Run Code Online (Sandbox Code Playgroud)

  • 是的,当然可以实施。我不明白,为什么*默认*行为如此无语。例如,如果“MailboxProcessor.add_Error”中没有处理程序,它可以重新抛出异常。调试异步/多线程代码很困难。为什么我们要让这项任务变得更加困难? (2认同)
  • 您可以争辩说,如果没有附加处理程序,最好取消该过程(未处理的异常).我不记得理由. (2认同)