gpt4 book ai didi

c# - C#中基于任务的异步方法的超时模式

转载 作者:太空狗 更新时间:2023-10-29 18:05:20 24 4
gpt4 key购买 nike

据我所知,有两种可能的模式可以实现基于任务的异步方法的超时:

内置超时

public Task DoStuffAsync(TimeSpan timeout)

这种方法更难实现,因为要为整个调用堆栈实现全局 超时并不容易。例如,Web API Controller 接收到一个 HTTP 请求并调用 DoStuffAsync,而调用者想要 3 秒的全局超时。

也就是说,每个内部异步方法调用都需要减去已使用的时间...

没有内置超时

public Task DoStuffAsync(CancellationToken cancellationToken)

..........

CancellationTokenSource cancellationSource = new CancellationTokenSource();
Task timeoutTask = Task.Delay(3000);

if(await Task.WhenAny(DoStuffAsync(cancellationTokenSource), timeoutTask) == timeoutTask)
{
cancellationSource.Cancel();

throw new TimeoutException();
}

这似乎是最可靠和最容易实现的模式。第一个调用者定义了一个全局超时,如果它超时,所有挂起的操作都将被取消。此外,它向直接调用者提供取消 token ,内部调用将共享相同的取消 token 引用。因此,如果顶级调用者超时,它将能够取消任何工作线程。

整个问题

如果我使用 无内置超时 开发 API,我是否遗漏了任何模式,或者我的方法是否正确?

最佳答案

虽然您可以为取消和超时重用 WithCancellation,但我认为这对您的需求来说有点矫枉过正。

async 操作超时的更简单、更清晰的解决方案是使用 Task.WhenAny await 实际操作和超时任务.如果超时任务先完成,您就超时了。否则,操作成功完成:

public static async Task<TResult> WithTimeout<TResult>(this Task<TResult> task, TimeSpan timeout)
{
if (task == await Task.WhenAny(task, Task.Delay(timeout)))
{
return await task;
}
throw new TimeoutException();
}

用法:

try
{
await DoStuffAsync().WithTimeout(TimeSpan.FromSeconds(5));
}
catch (TimeoutException)
{
// Handle timeout.
}

如果你不想抛出异常(就像我一样),那就更简单了,只需返回默认值:

public static Task<TResult> WithTimeout<TResult>(this Task<TResult> task, TimeSpan timeout)
{
var timeoutTask = Task.Delay(timeout).ContinueWith(_ => default(TResult), TaskContinuationOptions.ExecuteSynchronously);
return Task.WhenAny(task, timeoutTask).Unwrap();
}

关于c# - C#中基于任务的异步方法的超时模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25683980/

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