私は楽しみと利益のために 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 のみであるかどうかについて: 次のループで何が起こるか、それぞれ 200ms、2500ms、4000ms スリープすると? 真ん中に印刷されますか?
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"
}