在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)

但我想在这里等待只是出于提问的目的,而您实际上正在执行其他一些(可能可以取消,也可能不是)操作。


以上是在FromContinuations中使用取消延续的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>