簡體   English   中英

Async.Catch不適用於OperationCanceledExceptions

[英]Async.Catch doesnt work on OperationCanceledExceptions

我使用Async.Catch來處理異步工作流拋出的異常:

work
|> Async.Catch
|> Async.RunSynchronously
|> fun x -> match x with
            | Choice1Of2 _ -> () // success
            | Choice2Of2 ex -> // failure, handle exception

今天我注意到Async.Catch不處理OperationCanceledExceptions。 而不是從Async.Catch獲得選擇,異常不斷冒泡直到它擊中我。 我希望下面的測試是紅色的,但它是綠色的:

  [<Test>]
  let ``Async.Catch doesnt work on OperationCancelledExceptions``() =
    use cancellationTokenSource = new System.Threading.CancellationTokenSource(1000)

    let work = async {
      while true do
        do! Async.Sleep 100
    }

    (fun () -> work
               |> Async.Catch
               |> fun x -> Async.RunSynchronously (x, cancellationToken=cancellationTokenSource.Token)
               |> ignore)
    |> should throw typeof<System.OperationCanceledException>

使用Async.Catch + Choices +匹配以及其他一些使用try / catch塊評估一些異常似乎不正確......它看起來像下面這樣,這太復雜了。 除此之外,我想知道Async.Catch有什么用,因為我必須使用try / catch塊...:

  [<Test>]
  let ``evaluating exceptions of async workflows``() =
    use cancellationTokenSource = new System.Threading.CancellationTokenSource(1000)

    let work = async {
      while true do
        do! Async.Sleep 100
    }

    try
      work
      |> Async.Catch
      |> fun x -> Async.RunSynchronously (x, cancellationToken=cancellationTokenSource.Token)
      |> fun x -> match x with
                  | Choice1Of2 result -> () // success, process result
                  | Choice2Of2 ex -> () // failure, handle exception
    with ex -> () // another failure, handle exception here too

處理異步工作流異常的最佳方法是什么? 我應該只是轉儲Async.Catch並在任何地方使用try / catch塊嗎?

取消是異步計算中的一種特殊異常。 取消工作流時,這也會取消所有子計算(共享取消令牌)。 因此,如果您可以將取消作為一個普通的例外處理,它仍然可以取消計算的其他部分(並且很難推斷出正在發生的事情)。

但是,您可以編寫啟動工作流的基元(並將其與父工作流分開),然后在此子工作流中處理取消。

type Async = 
  static member StartCatchCancellation(work, ?cancellationToken) = 
    Async.FromContinuations(fun (cont, econt, _) ->
      // When the child is cancelled, report OperationCancelled
      // as an ordinary exception to "error continuation" rather
      // than using "cancellation continuation"
      let ccont e = econt e
      // Start the workflow using a provided cancellation token
      Async.StartWithContinuations( work, cont, econt, ccont, 
                                    ?cancellationToken=cancellationToken) )

用法類似於Async.Catch ,但您必須將取消令牌傳遞給StartCatchCancellation而不是將其傳遞給主RunSynchronously (因為工作流是單獨啟動的):

let work = 
  async { while true do
            do! Async.Sleep 100 }

let ct = new System.Threading.CancellationTokenSource(10000)
Async.StartCatchCancellation(work, ct.Token) 
|> Async.Catch
|> Async.RunSynchronously 
|> printfn "%A"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM