asynchronous - F# 中的协作取消与取消延续

标签 asynchronous f# cancellation

我可能有两个问题而不是一个,但无论如何。

我正在将合作取消实现为 here suggested 。这是我的测试代码:

type Async with
    static member Isolate(f : CancellationToken -> Async<'T>) : Async<'T> =
        async {
            let! ct = Async.CancellationToken
            let isolatedTask = Async.StartAsTask(f ct)
            return! Async.AwaitTask isolatedTask
        }

let testLoop (ct: CancellationToken) = async {
    let rec next ix =
        if ct.IsCancellationRequested then ()
        else 
            printf "%i.." ix
            Thread.Sleep 10  
            next (ix+1)
    next 1
}

let cancellationSource = new CancellationTokenSource()
let onDone () = printfn "!! DONE"
let onError _ = printfn "!! ERROR"
let onCancel _ = printfn "!! CANCEL"

Async.StartWithContinuations (Async.Isolate testLoop, onDone, onError, onCancel, cancellationSource.Token)

Thread.Sleep(100)
cancellationSource.Cancel ()
Thread.Sleep(500)

如您所见,我以完成取消错误延续开始异步。如果我按原样运行该代码,我将得到以下输出:

1..2..3..4..5..6..7..8..!! DONE

如果我稍微更新 Isolate 方法,如下所示:

    static member Isolate(f : CancellationToken -> Async<'T>) : Async<'T> =
        async {
            let! ct = Async.CancellationToken
            let isolatedTask = Async.StartAsTask(f ct)
            let! x = Async.AwaitTask isolatedTask
            x
        }

我得到了预期的(我自己)输出:

1..2..3..4..5..6..7..!! CANCEL

为什么我们的行为会有如此差异?

如果在一段时间内没有取消,是否可以中止testLoop

最佳答案

async block 仅在绑定(bind)之前和之后检查 Async.CancellationToken 的取消(使用 let! 编写)。这意味着当 token 被取消时,只有当有更多工作要做时工作流程才会被取消。

还值得注意的是,在此示例中,isolatedTask 本身并未被取消,因为它只是定期终止(使用 if)。

就您而言:

  • 当您仅使用 return! 时,任务定期返回,Async.AwaitTask 定期返回,之后不执行任何操作,因此工作流程完成。

  • 当您使用 let! 后跟 return 时,任务会定期返回,并且 Async.AwaitTask 会定期返回,但是let! 在运行 return 之前检查取消情况,这会取消工作流程。

关于asynchronous - F# 中的协作取消与取消延续,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37596011/

相关文章:

javascript - 返回未决的 promise 有实际好处吗?

python - 所有任务完成后如何终止 python asyncio event_loop

F# Map.add 时间和空间复杂度

javascript - 如何取消 Javascript Promise 中的超时?

c# - SemaphoreSlim 取消 token

logging - 如何使用 core.async 在 Clojure 中写入日志文件?

ios - 具有异步网络请求的Swift 2 For Loop在响应后继续循环

F# 按元素对两个序列求和

parameters - F#管道第一个参数

linux - POSIX 线程何时取消不立即?