F#中的协作取消和取消继续 [英] Cooperative cancellation in F# with cancel continuation

查看:55
本文介绍了F#中的协作取消和取消继续的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可能我在这里有2个问题,而不是一个问题.

我正在按照此处建议的方式实施合作取消.这是我的测试代码:

I'm implementing cooperative cancellation as here suggested. Here is my test code:

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)

如您所见,我从完成取消 error 延续开始异步.如果按原样运行该代码,则会得到以下输出:

As you can see, I start async with done, cancel and error continuations. If I run that code as is, I'll get the following output:

1..2..3..4..5..6..7..8 .. !!完成

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

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

If I slightly update the Isolate method as follows:

    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 .. !!取消

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

我们为什么在行为上有这种差异?

Why do we have such difference in the behavior?

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

Is it possible to abort the testLoop, if it does not cancelled within some timeout?

推荐答案

async 块仅在绑定之前和之后检查是否取消了 Async.CancellationToken (使用 let!).这意味着当令牌被取消时,只有在还有更多工作要做时,工作流程才会被取消.

The async block checks for cancellation of the Async.CancellationToken only before and after bind (written using let!). This means that when the token gets cancelled, the workflow will only get cancelled when there is more work to be done.

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

It is also worth noting that isolatedTask does not itself gets cancelled in this example, because it just terminates regularly (using if).

在您的情况下:

  • 仅使用 return!时,任务会定期返回, Async.AwaitTask 会定期返回,此后什么也不做,因此工作流完成.

  • When you use just return!, the task returns regularly, Async.AwaitTask returns regularly and nothing is done afterwards so the workflow completes.

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

When you use let! followed by return, the task returns regularly and Async.AwaitTask returns regularly, but then let! checks for cancellation before running return and this cancels the workflow.

这篇关于F#中的协作取消和取消继续的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆