来自异步工作流的Catch异常在不同的线程上运行

时间:2015-06-10 16:56:52

标签: asynchronous f#

let failing = async {
    failwith "foo"
}

let test () =
    try
        Async.Start(failing)
    with
    | exn -> printf "caught"

此代码没有捕获异常。如何在单独的线程上启动异步工作流并捕获主程序中的异常?

2 个答案:

答案 0 :(得分:0)

由于没有等待的结果,因此没有可以捕获异常的地方。你需要包装计算。一种可能性:

let failing = async {
    failwith "foo"
}

let test () = 
    async {
        let! res = failing |> Async.Catch
        match res with
        | Choice1Of2 _ -> printf "success"
        | Choice2Of2 exn -> printfn "failed with %s" exn.Message
    } |> Async.Start

答案 1 :(得分:0)

作为替代方案,您可以将工作流作为任务启动,并使用它的方法和属性。例如,Task.Result将再次重新抛出异常,因此这很有效,几乎是您尝试过的:

let test () = 
   try 
      Async.StartAsTask failing 
      |> fun t -> t.Result
   with _ -> printfn "caught"

运行

> test ();;
caught
val it : unit = ()

在不同的线程上

抱歉 - 我刚看到你想要它在另一个线程上 - 在这种情况下你很可能想要使用RCH给你的内部方法 - 但你也可以使用ContinueWith(虽然有点难看):

open System.Threading.Tasks

let test () = 
   (Async.StartAsTask failing).ContinueWith(fun (t : Task<_>) -> try t.Result with _ -> printfn "caught")

运行

> test ();;
caught
val it : Task = System.Threading.Tasks.Task {AsyncState = null;
                                             CreationOptions = None;
                                             Exception = null;
                                             Id = 3;
                                             IsCanceled = false;
                                             IsCompleted = true;
                                             IsFaulted = false;
                                             Status = RanToCompletion;}

没有Async.Catch

你也不需要Async.Catch

let test () = 
   async { 
      try 
         do! failing 
      with _ -> printfn "caught" 
   } |> Async.Start