在FromContinuations中使用取消延续
f#
我正在尝试async通过Async<'T>I create with了解工作流程Async.FromContinuations,但看不到如何使用取消延续。我正在尝试这个:
open System
let asyncComputation divisor =
Async.FromContinuations
(fun (success, except, cancel) ->
try
printfn "Going to sleep..."
Threading.Thread.Sleep 3000
printfn "...waking up"
1 / divisor |> ignore
printfn "Calling success continuation..."
success ()
with
| :? OperationCanceledException as e ->
printfn "Calling cancellation continuation..."
cancel e
| e ->
printfn "Calling exception continuation..."
except e)
[<EntryPoint>]
let main argv =
use tokenSource = new Threading.CancellationTokenSource ()
Async.Start (asyncComputation (int argv.[0]), tokenSource.Token)
Console.ReadLine () |> ignore
tokenSource.Cancel ()
带参数运行1会导致在唤醒后调用成功继续;并使用参数运行0会导致在唤醒后调用异常继续,从而产生预期的异常输出。到现在为止还挺好。但是当我Enter在 3 秒睡眠期间通过按下键取消(使用任一参数)时,它显然取消了异步计算而不调用取消继续。那么应该如何在 中使用取消延续FromContinuations,以及应该如何触发取消以便它调用取消延续呢?
回答
如果您CancellationToken在异步计算中使用,F# 异步工作流将自动传播它,以便您可以在任何地方访问它,但您仍然需要明确检查是否已触发取消并自己抛出异常。这不会在同步用户代码的任何地方“自动”发生。
这意味着问题有两个部分。1) 如何访问取消令牌和 2) 如何检查它是否已被取消。
第二部分有点棘手,因为您需要使用Async.CancellationToken,但这会返回Async<CancellationToken>,因此您必须在FromContinuations代码之外的异步块中调用它。第二部分只是tok.ThrowIfCancellationRequested()在代码中的某个地方调用的问题。
以下在执行除法之前检查取消:
let asyncComputation divisor = async {
let! tok = Async.CancellationToken
return! Async.FromContinuations
(fun (success, except, cancel) ->
try
printfn "Going to sleep..."
Threading.Thread.Sleep 3000
printfn "...waking up"
tok.ThrowIfCancellationRequested()
1 / divisor |> ignore
printfn "Calling success continuation..."
success ()
with
| :? OperationCanceledException as e ->
printfn "Calling cancellation continuation..."
cancel e
| e ->
printfn "Calling exception continuation..."
except e) }
这不会在等待时取消。如果你想这样做,你需要能够取消等待操作,例如使用类似的东西:
Async.RunSynchronously(Async.Sleep 3000, cancellationToken = tok)
但我想在这里等待只是出于提问的目的,而您实际上正在执行其他一些(可能可以取消,也可能不是)操作。