在Async.FromContinuations声明中获取取消令牌

时间:2012-09-20 22:30:52

标签: f# cancellation-token

考虑以下定义

let test =
    Async.FromContinuations(
        fun (cont,econt,ccont) ->
            let rec inner () =
                async {
                    do printfn "looping..."
                    do! Async.Sleep 1000
                    return! inner ()
                }

            Async.Start(inner ())
            cont ())

假设我想尝试这样的计算

let cts = new CancellationTokenSource ()
Async.Start(test, cts.Token)
cts.Cancel()

这自然不会使内循环停止,因为我没有通过合适的取消令牌。有什么办法可以通过Async.FromContinuations获取外部取消令牌吗?我可以使用异步构建器和Async.CancellationToken重写它,但是我将失去将continuation传递给内部表达式的能力。

2 个答案:

答案 0 :(得分:2)

像这样??

let test =
    async {
        let! ct = Async.CancellationToken
        return! Async.FromContinuations(
            fun (cont,econt,ccont) ->
                let rec inner () =
                    async {
                        do printfn "looping..."
                        do! Async.Sleep 1000
                        return! inner ()
                    }

                Async.Start(inner (), cancellationToken = ct)
                cont ())
    }
let cts = new CancellationTokenSource ()
Async.Start(test, cts.Token)
cts.CancelAfter(1000)

答案 1 :(得分:2)

你能描述一下你想做什么吗?如果我正确理解您的代码,您希望在后台启动inner循环函数,然后并行继续运行工作流的其余部分(使用cont()调用)。

为此,您不需要Async.FromContinuations。有一个函数正是这个,它还负责处理异常,取消令牌等。

我认为你可以像这样重写你的程序:

let test = 
    // The inner loop function from your example
    let rec inner () = async { 
        do printfn "looping..." 
        do! Async.Sleep 1000 
        return! inner ()  } 

    async { 
      // Start the inner loop as a child async 
      let! _ = Async.StartChild(inner())
      // ... continue doing other things in parllel if you wish
      do printfn "main body running..." }

计算的启动和取消与以前一样:

let cts = new CancellationTokenSource () 
Async.Start(test, cts.Token) 
// This will cancel the 'inner' loop as well
cts.Cancel() 

如果使用Async.StartChild来呼叫let!,它将启动内部任务,向其传递取消令牌等。它会返回一个令牌,您可以稍后使用该令牌等待子任务完成,但是因为你没有这样做,我使用了_模式。