Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Exception handling Async.Catch对OperationCanceledException不起作用_Exception Handling_F#_Async Workflow - Fatal编程技术网

Exception handling Async.Catch对OperationCanceledException不起作用

Exception handling Async.Catch对OperationCanceledException不起作用,exception-handling,f#,async-workflow,Exception Handling,F#,Async Workflow,我使用Async.Catch处理异步工作流引发的异常: work |> Async.Catch |> Async.RunSynchronously |> fun x -> match x with | Choice1Of2 _ -> () // success | Choice2Of2 ex -> // failure, handle exception 今天我注意到OperationCanceledExcep

我使用Async.Catch处理异步工作流引发的异常:

work
|> Async.Catch
|> Async.RunSynchronously
|> fun x -> match x with
            | Choice1Of2 _ -> () // success
            | Choice2Of2 ex -> // failure, handle exception
今天我注意到OperationCanceledException不是由Async.Catch处理的。而不是从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在OperationCancelledExceptions”上不起作用()=
使用cancellationTokenSource=new System.Threading.cancellationTokenSource(1000)
让工作=异步{
尽管如此
做!异步。睡眠100
}
(乐趣()->工作
|>异步捕获
|>fun x->Async.RunSynchronously(x,cancellationToken=cancellationTokenSource.Token)
|>忽略)
|>应该抛出类型
使用Async.Catch+Choices+matching评估某些异常,使用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
[]
让“`评估异步工作流的异常”`()=
使用cancellationTokenSource=new System.Threading.cancellationTokenSource(1000)
让工作=异步{
尽管如此
做!异步。睡眠100
}
尝试
工作
|>异步捕获
|>fun x->Async.RunSynchronously(x,cancellationToken=cancellationTokenSource.Token)
|>乐趣x->将x与
|Choice1Of2结果->()//成功,处理结果
|Choice2Of2 ex->()//失败,处理异常
使用ex->()//另一个失败,在这里也处理异常

处理异步工作流异常的最佳方法是什么?我应该转储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
,但您必须将取消令牌传递给
startcachcancellation
,而不是将其传递给同步运行的主
(因为工作流是单独启动的):


谢谢你的解释,有道理。您还回答了我的另一个问题:“当工作流被取消时,这也会取消所有子计算”。我想问这个问题,因为MSDN文档没有告诉当其父计算被取消时,子计算会发生什么。
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"