1

考虑以下定义

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 重写它,但是我将失去将延续传递给内部表达式的能力。

4

2 回答 2

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)
于 2012-09-20T22:53:16.093 回答
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.StartChildusinglet!那么它将启动内部任务,将取消令牌传递给它等。它返回一个令牌,您可以稍后使用该令牌等待子任务完成,但由于您没有这样做,所以我使用了该_模式。

于 2012-09-21T10:41:37.653 回答