[英]MailboxProcessor and exceptions
我想知道,為什么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
沒有任何反應。 程序執行沒有致命的停止,或者出現帶有“未處理的異常”的消息框。 沒有。
如果有人使用PostAndReply
方法,這種情況會變得更糟:結果是保證死鎖。
這種行為有什么理由嗎?
MailboxProcessor上有一個Error
事件。
http://msdn.microsoft.com/en-us/library/ee340481
counter.Error.Add(fun e -> printfn "%A" e)
當然,如果你想自己施加精細控制,你可以做一些類似Tomas的解決方案。
我認為F#中的MailboxProcessor
不包含任何處理異常的機制的原因是,目前尚不清楚這樣做的最佳方法是什么。 例如,您可能希望在發生未處理的異常時觸發全局事件,但您可能希望在下次調用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
要使用它,您將編寫與之前編寫的代碼相同的代碼,但您現在可以異步處理異常:
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)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.