Reputation: 4594
I'm reading F# for fun and profit - Asynchronous programming. Under Cancelling workflows they have the following example:
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()
About this they say:
In F#, any nested async call will check the cancellation token automatically!
In this case it was the line:
do! Async.Sleep(10)
As you can see from the output, this line is where the cancellation happened.
However, for me (VS2010, F# 2.0, F# Interactive) I get the following output. Notice how it also prints ..after
after I have canceled the token. Are they simply wrong?
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
So perhaps the check for cancellation is done when entering Async.Sleep
? No, then it would've printed:
13 before....after
14 before..
val cancellationSource : CancellationTokenSource
>
So it seems like the check is actually in the for-loop! I.e. it keeps running until the for loop after being cancelled. Is this how it works? What then if I'd rather want it to check after the sleep?
This question seems to hint at cancellation working like I described above: Can I explicitly check for cancellation / terminate async computation?
Edit: Regarding if this is only in FSI 2.0: What happens with the following loop, if one sleep 200ms, 2500ms and 4000ms respectively? Does it print middle?
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"
}
Upvotes: 11
Views: 2317
Reputation: 3697
I see the same results as you with F# 2.0 only in interactive Fsi. If I put the same code in a file and run fsi cancel.fsx
, then the output does not have the final after
and is what you expect.
Fsi v11 and v12 show the expected output for both ways of running the code.
This suggests there is some bug or difference when running Fsi v2.0 interactively that was fixed in a later version of FSharp.
Upvotes: 2