F#中的合作取消取消继续

时间:2016-06-02 15:23:53

标签: 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,如果在某些超时内没有取消?

1 个答案:

答案 0 :(得分:3)

async块仅在绑定之前和之后检查Async.CancellationToken的取消(使用let!编写)。这意味着当令牌被取消时,工作流将仅在需要完成更多工作时被取消。

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

在你的情况下:

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

  • 当您使用let!后跟return时,任务会定期返回,Async.AwaitTask会定期返回,但之后let!会检查取消 < / em>正在运行return,这会取消工作流程。