9

我正在阅读F# 以获取乐趣和利润 - 异步编程。在取消工作流程下,他们有以下示例:

let testLoop = async {
    for i in [1..100] do
    // do something
    printf "%i before.." i
    
    // sleep a bit 
    do! Async.Sleep 10  
    printfn "..after"
    }

open System
open System.Threading

// create a cancellation source
let cancellationSource = new CancellationTokenSource()

// start the task, but this time pass in a cancellation token
Async.Start (testLoop,cancellationSource.Token)

// wait a bit
Thread.Sleep(200)  

// cancel after 200ms
cancellationSource.Cancel()

关于这一点,他们说:

在 F# 中,任何嵌套的异步调用都会自动检查取消令牌!

在这种情况下,它是行:

do! Async.Sleep(10) 

从输出中可以看出,这一行是取消发生的地方。

但是,对我来说(VS2010、F# 2.0、F# Interactive)我得到以下输出。..after请注意在我取消令牌后它是如何打印的。他们只是错了吗?

1 before....after
2 before....after
3 before....after
4 before....after
5 before....after
6 before....after
7 before....after
8 before....after
9 before....after
10 before....after
11 before....after
12 before....after
13 before..
val cancellationSource : CancellationTokenSource

>
..after

所以也许在进入 时检查取消Async.Sleep?不,那么它会打印:

13 before....after
14 before..
val cancellationSource : CancellationTokenSource

>

所以看起来检查实际上是在for循环中!即它一直运行,直到被取消后的for循环。这是它的工作原理吗?那么如果我希望它在睡眠后检查呢?

这个问题似乎暗示了我上面描述的取消工作:我可以显式检查取消/终止异步计算吗?

编辑:关于这是否仅在 FSI 2.0 中:如果一个循环分别睡 200 毫秒、2500 毫秒和 4000 毫秒,会发生什么情况?它打印在中间吗?

let testLoop = async {
    for i in [1..5] do
    printf "%i before.." i
    do! Async.Sleep 2000
    printfn "..middle.."
    do! Async.Sleep 1000  
    printfn "..after"
    }
4

1 回答 1

2

我只在交互式 Fsi 中看到与 F# 2.0 相同的结果。如果我将相同的代码放在文件中并运行fsi cancel.fsx,则输出没有最终结果after,并且是您所期望的。

Fsi v11 和 v12 显示了两种运行代码方式的预期输出。

这表明在以交互方式运行 Fsi v2.0 时存在一些错误或差异,这些错误或差异已在 FSharp 的更高版本中修复。

于 2014-01-17T15:10:04.310 回答