问题描述
可能我在这里有2个问题,而不是一个问题.
我正在按照此处建议的方式实施合作取消.这是我的测试代码:
I'm implementing cooperative cancellation as here suggested. Here is my test code:
type Async with
static member Isolate(f : CancellationToken -> Async<'T>) : Async<'T> =
async {
let! ct = Async.CancellationToken
let isolatedTask = Async.StartAsTask(f ct)
return! Async.AwaitTask isolatedTask
}
let testLoop (ct: CancellationToken) = async {
let rec next ix =
if ct.IsCancellationRequested then ()
else
printf "%i.." ix
Thread.Sleep 10
next (ix+1)
next 1
}
let cancellationSource = new CancellationTokenSource()
let onDone () = printfn "!! DONE"
let onError _ = printfn "!! ERROR"
let onCancel _ = printfn "!! CANCEL"
Async.StartWithContinuations (Async.Isolate testLoop, onDone, onError, onCancel, cancellationSource.Token)
Thread.Sleep(100)
cancellationSource.Cancel ()
Thread.Sleep(500)
如您所见,我从完成,取消和 error 延续开始异步.如果按原样运行该代码,则会得到以下输出:
As you can see, I start async with done, cancel and error continuations. If I run that code as is, I'll get the following output:
如果我稍微更新 Isolate
方法,如下所示:
If I slightly update the Isolate
method as follows:
static member Isolate(f : CancellationToken -> Async<'T>) : Async<'T> =
async {
let! ct = Async.CancellationToken
let isolatedTask = Async.StartAsTask(f ct)
let! x = Async.AwaitTask isolatedTask
x
}
我得到了预期的输出:
我们为什么在行为上有这种差异?
Why do we have such difference in the behavior?
如果在一段时间内没有取消 testLoop
,是否可以中止它?
Is it possible to abort the testLoop
, if it does not cancelled within some timeout?
推荐答案
async
块仅在绑定之前和之后检查是否取消了 Async.CancellationToken
(使用 let!
).这意味着当令牌被取消时,只有在还有更多工作要做时,工作流程才会被取消.
The async
block checks for cancellation of the Async.CancellationToken
only before and after bind (written using let!
). This means that when the token gets cancelled, the workflow will only get cancelled when there is more work to be done.
还值得注意的是,在此示例中, isolatedTask
本身并没有被取消,因为它只是定期终止(使用 if
).
It is also worth noting that isolatedTask
does not itself gets cancelled in this example, because it just terminates regularly (using if
).
在您的情况下:
-
仅使用
return!
时,任务会定期返回,Async.AwaitTask
会定期返回,此后什么也不做,因此工作流完成.
When you use just
return!
, the task returns regularly,Async.AwaitTask
returns regularly and nothing is done afterwards so the workflow completes.
当您使用 let!
后跟 return
时,任务会定期返回,而 Async.AwaitTask
会定期返回,但随后< let!
在运行 return
之前在 之前检查取消,这会取消工作流程.
When you use let!
followed by return
, the task returns regularly and Async.AwaitTask
returns regularly, but then let!
checks for cancellation before running return
and this cancels the workflow.
这篇关于F#中的协作取消和取消继续的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!