问题描述
我想知道为什么MailboxProcessor
处理异常的默认策略只是静默地忽略.例如:
I wonder, why MailboxProcessor
's default strategy of handling exceptions is just silently ignore them. For example:
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
什么也没有发生.不会致命地停止程序执行,否则会出现带有未处理的异常"的消息框.没事.
and nothing happens. There is no fatal stop of the program execution, or message box with "An unhandled exception" arises. Nothing.
如果有人使用PostAndReply
方法,这种情况会变得更糟:结果是有保证的死锁.
This situation becomes worse if someone uses PostAndReply
method: a guaranteed deadlock as the result.
有任何这种行为的原因吗?
Any reasons for such behavior?
推荐答案
我认为F#中的MailboxProcessor
不包含任何处理异常的机制的原因在于,目前尚不清楚什么是最好的处理方式.例如,您可能想让一个全局事件在发生未处理的异常时触发,但您可能想在下一次调用Post
或PostAndReply
时将异常重新抛出.
I think the reason why the MailboxProcessor
in F# does not contain any mechanism for handling exceptions is that it is not clear what is the best way for doing that. For example, you may want to have a global event that is triggered when an unhandled exception happens, but you may want to rethrow the exception on the next call to Post
or PostAndReply
.
这两个选项都可以基于标准MailboxProcessor
实现,因此可以添加所需的行为.例如,以下代码片段显示了HandlingMailbox
,它添加了一个全局异常处理程序.它具有与普通MailboxProcessor
相同的接口(我省略了一些方法),但是它添加了OnError
事件,该事件在发生异常时触发:
Both of the options can be implemented based on the standard MailboxProcessor
, so it is possible to add the behaviour you want. For example, the following snippet shows HandlingMailbox
that adds a global exception handler. It has the same interface as normal MailboxProcessor
(I omitted some methods), but it adds OnError
event that is triggered when an exception happens:
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
要使用它,您将编写与以前编写的代码相同的代码,但现在可以异步处理异常:
To use it, you would write the same code as what you wrote before, but you can now handle exceptions asynchronously:
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)
这篇关于MailboxProcessor和异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!