gpt4 book ai didi

F# Async.RunSynchronously 带有超时和取消 token

转载 作者:行者123 更新时间:2023-12-04 22:48:24 25 4
gpt4 key购买 nike

当使用超时和 CancellationToken 调用 Async.RunSynchronously 时,超时值似乎被忽略。我可以通过在 CancellationToken 上调用 CancelAfter 来解决这个问题,但理想情况下我希望能够区分工作流中发生的异常 TimeOutExceptions 和 OperationCanceledExceptions。

我相信下面的示例代码证明了这一点。

open System
open System.Threading

let work =
async {
let endTime = DateTime.UtcNow.AddMilliseconds(100.0)
while DateTime.UtcNow < endTime do
do! Async.Sleep(10)
Console.WriteLine "working..."
raise ( Exception "worked for more than 100 millis" )
}


[<EntryPoint>]
let main argv =
try
Async.RunSynchronously(work, 50)
with
| e -> Console.WriteLine (e.GetType().Name + ": " + e.Message)

let cts = new CancellationTokenSource()

try
Async.RunSynchronously(work, 50, cts.Token)
with
| e -> Console.WriteLine (e.GetType().Name + ": " + e.Message)


cts.CancelAfter(80)
try
Async.RunSynchronously(work, 50, cts.Token)
with
| e -> Console.WriteLine (e.GetType().Name + ": " + e.Message)

Console.ReadKey(true) |> ignore

0

输出如下,显示超时仅在第一种情况下有效(未指定 CancelationToken)
working...
working...
TimeoutException: The operation has timed out.
working...
working...
working...
working...
working...
working...
working...
Exception: worked for more than 100 millis
working...
working...
working...
working...
working...
working...
OperationCanceledException: The operation was canceled.

这是预期的行为吗?有什么办法可以得到我所追求的行为吗?

谢谢!

最佳答案

我不确定这是否是预期行为 - 至少,我看不出任何原因。但是,这种行为是直接在RunSynchronously 的参数处理中实现的。 .如果你看 library source code ,你可以看到:

static member RunSynchronously (p:Async<'T>,?timeout,?cancellationToken) =
let timeout,token =
match cancellationToken with
| None -> timeout,(!defaultCancellationTokenSource).Token
| Some token when not token.CanBeCanceled -> timeout, token
| Some token -> None, token

在您的情况下(超时和可以取消的取消 token ),代码通过最后一个分支并忽略超时。我认为这要么是一个错误,要么应该在文档中提及。

作为解决方法,您可以创建一个单独的 CancellationTokenSource指定超时并将其链接到主取消源,以便调用者提供(使用 CreateLinkedTokenSource )。当您收到 OperationCancelledException ,然后您可以检测源是实际取消还是超时:
type Microsoft.FSharp.Control.Async with
static member RunSynchronouslyEx(a:Async<'T>, timeout:int, cancellationToken) =
// Create cancellation token that is cancelled after 'timeout'
let timeoutCts = new CancellationTokenSource()
timeoutCts.CancelAfter(timeout)

// Create a combined token that is cancelled either when
// 'cancellationToken' is cancelled, or after a timeout
let combinedCts =
CancellationTokenSource.CreateLinkedTokenSource
(cancellationToken, timeoutCts.Token)

// Run synchronously with the combined token
try Async.RunSynchronously(a, cancellationToken = combinedCts.Token)
with :? OperationCanceledException as e ->
// If the timeout occurred, then we throw timeout exception instead
if timeoutCts.IsCancellationRequested then
raise (new System.TimeoutException())
else reraise()

关于F# Async.RunSynchronously 带有超时和取消 token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14439292/

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