gpt4 book ai didi

asynchronous - 有什么原因不能立即取消 Async.Sleep 吗?

转载 作者:行者123 更新时间:2023-12-04 05:26:44 25 4
gpt4 key购买 nike

下面的测试表明 F# 2.0 中的 Async.Sleep 不能立即取消。只有在时间过去后,我们才会收到“取消”通知。

module async_sleep_test
open System
open System.Threading
open System.Threading.Tasks
open System.Xml

let cts = new CancellationTokenSource()
Task.Factory.StartNew(fun () ->
try
Async.RunSynchronously(async{
printfn "going to sleep"
do! Async.Sleep(10000)
}, -1(*no timeout*), cts.Token)
printfn "sleep completed"
with
| :? OperationCanceledException ->
printfn "sleep aborted" // we will see it only after 10 sec.
| _ ->
printfn "sleep raised error"
) |> ignore
Thread.Sleep(100) // give time to the task to enter in sleep
cts.Cancel()
Thread.Sleep(100) // give chance to the task to complete before print bye message
printfn "press any key to exit...."
Console.ReadKey(true) |> ignore

我认为这是不正确的行为。你怎么认为这是一个错误?例如,如果我将使用以下实现,会不会有任何意外:
static member SleepEx(milliseconds:int) = async{
let disp = new SerialDisposable()
use! ch = Async.OnCancel(fun()->disp.Dispose())
do! Async.FromContinuations(fun (success, error, cancel) ->
let timerSubscription = new SerialDisposable()
let CompleteWith =
let completed = ref 0
fun cont ->
if Interlocked.Exchange(completed, 1) = 0 then
timerSubscription.Dispose()
try cont() with _->()

disp.Disposable <- Disposable.Create(fun()->
CompleteWith (fun ()-> cancel(new OperationCanceledException()))
)
let tmr = new Timer(
callback = (fun state -> CompleteWith(success)),
state = null, dueTime = milliseconds, period = Timeout.Infinite
)
if tmr = null then
CompleteWith(fun ()->error(new Exception("failed to create timer")))
else
timerSubscription.Disposable <- Disposable.Create(fun()->
try tmr.Dispose() with _ -> ()
)
)
}

最佳答案

我不会说这是一个错误 - 它遵循一般在 F# 异步工作流中处理取消的方式。通常,F# 假定您使用 let! 调用的原始操作或 do!不支持取消(我猜在 .NET 中没有标准机制),因此 F# 在使用 let! 进行的调用之前和之后插入取消检查。 .

所以打个电话let! res = foo()实际上更像是以下内容(尽管检查隐藏在 async 的库实现中):

token.ThrowIfCancellationRequested()
let! res = foo()
token.ThrowIfCancellationRequested()

当然是 foo()返回的工作流可以更好地处理取消 - 通常,如果它是使用 async { .. } 实现的块,那么它将在每个 let! 周围包含更多检查.但是,一般情况下(除非某些操作以更聪明的方式实现),取消会在下一个 let! 之后执行。调用完成。

您对 Sleep 的替代定义对我来说看起来不错 - 它比 F# 库中可用的更好地支持取消,如果您需要立即取消,然后替换 F# 的 Async.Sleep与您的 SleepEx是唯一的出路。但是,可能仍然会有一些不支持立即取消的操作,因此您可能会在其他地方遇到问题(如果您到处都需要这种行为)。

PS:我想你的 SleepEx功能可能对其他人非常有用。如果您可以在 F# Snippets web site 上分享它,那太棒了!

关于asynchronous - 有什么原因不能立即取消 Async.Sleep 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9041491/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com