Вопрос по – MailboxProcessor и исключения

14

Интересно, почемуMailboxProcessorстандартная стратегия обработки исключений простоsilently ignore их. Например:

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 метод: гарантированный тупик в результате.

Есть ли причины для такого поведения?

Ваш Ответ

2   ответа
5

Я думаю, что причина, почемуMailboxProcessor в F # не содержится никакого механизма для обработки исключений, заключается в том, что не ясно, каков наилучший способ сделать это. Например, вы можете захотеть иметь глобальное событие, которое запускается при возникновении необработанного исключения, но вы можете захотеть сбросить исключение при следующем вызове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) 
Error: User Rate Limit Exceededasync{failwith "bad"}Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededdefaultError: User Rate Limit ExceededMailboxProcessor.add_ErrorError: User Rate Limit Exceeded qehgt
Error: User Rate Limit Exceeded
12

ЕстьError событие на MailboxProcessor.

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

counter.Error.Add(fun e -> printfn "%A" e)

Конечно, вы можете сделать что-то вроде Томаса & apos; решение, если вы хотите, чтобы контролировать себя.

Да, я знаю об этом участникеError, Интересно, почему по умолчанию обработчик ошибок ничего не делает. Он может перезапустить или записать в stderr, или остановить приложение - все лучше, чем просто игнорировать исключения. qehgt
Обратите внимание, что вы также можетеraise исключение вместо его печати, если вы хотите, чтобы ваша программа аварийно завершала работу приMailboxProcessor отказывает вместо того, чтобы продолжать работать в потенциально сломанном состоянии.
Doh! Я искал существующее событие по стандартуMailboxProcessor, но почему-то я полностью пропустилError событие...

Похожие вопросы