2014-10-07 2 views
1

Мой вопрос очень прост. Пожалуйста, обратите внимание на скриншоте:F # не может поймать TimeoutException

enter image description here

Как это могло произойти? Я прямо поставил вызов Async.RunSyncronously в try ... with.

+0

Может быть, я не понимаю, что правильно, но я подумал, что, делая это, я делаю так: 'async' начинается новый thread, и этот поток ждет завершения операции 'operation'. И это нормально для меня. Я мог бы использовать 'let!' Вместо этого, но 'let' не позволяет указывать тайм-аут, и для этого я и стремился. – Rustam

+1

Да, это так. Проблема может возникнуть из-за того, что моя 'операция' вызывает некоторые методы COM-объекта, и это всегда является источником сбоев. Но я не могу быть уверен в этом. – Rustam

ответ

1

try/with в F рабочих процессах # асинхронных не отображается непосредственно CLR защищенных блоки - вместо этого, если исключения возникают в коде пользователя, код библиотеки будет поймать его и изменить маршрут к продолжению ближайшей ошибки (которая может быть т.е. with block, finally block, продолжение пользовательской ошибки, поставляемое в Async.StartWithContinuations и т. д.). Это приводит к тому, что отладчик может сообщать о необработанных исключениях в коде пользователя, которые могут обрабатываться и обрабатываться позже.

Отрывок ниже сообщает подобную ошибку в отладчике, но тем не менее, выполнение завершается успешно

let error(): int = raise (System.TimeoutException()) 

let run() = async { 
    try 
     let result = error() 
     return result 
    with 
    :? System.TimeoutException -> return -1 
} 

let r = Async.RunSynchronously (run()) 
printfn "%d" r 
+0

Вау, это действительно интересно. Это побочный эффект реализации вычислительного выражения Async? И не могли бы вы предложить, что было бы лучшим способом поймать это проклятое исключение? Правильно ли это, что я должен перевести его в 'StartWithContinuations'? – Rustam

2

Попробуйте это:

let withTimeout (timeOut: option<int>) (operation: Async<'x>) : Async<option<'x>> = 
    match timeOut with 
    | None -> async { 
     let! result = operation 
     return Some result 
    } 
    | Some timeOut -> async { 
     let! child = Async.StartChild (operation, timeOut) 
     try 
     let! result = child 
     return Some result 
     with :? System.TimeoutException -> 
     return None 
    } 

Вы не должны использовать Async.RunSynchronously в async блоков, так как это делает для неоптимального использования собственных потоков и может привести к stack overflows. Async.RunSynchronously предназначено для выполнения вычислений вне таких вычислений Async. В блоке async вы можете использовать простые let! и do! или, например, Async.StartChild для запуска Async вычислений. Это обеспечивает более эффективное использование собственных потоков и не страдает от подобных проблем с потенциальными переполнениями стека.

+0

+1 Большое спасибо, это работает, я буду использовать вашу версию. Хотя по-прежнему интересно, почему моя версия не работает – Rustam

Смежные вопросы