January 13, 2020

C# 基于 async 的超时策略

方式一:让方法支持 CancellationTokenSource

public async Task Foo(CancellationToken token)
{
     if(token.IsCancellationRequested)
     {
        // 已取消操作
     }
     else
     {
        // 执行操作
     }
}

var timeout = 1000;
using (var cancelToken = new CancellationTokenSource(timeout))
{
    Foo(cancelToken.Token);
}

方式二:Task.Delay 并行执行

如果不能修改原方法,可在外面包装一层。原理是新增 Task.Delay 与任务 Task 并行执行,如果 Task.Delay 先结束则表示任务 Task 执行超时。

using (var cancelToken = new CancellationTokenSource())
{
    int timeout = 1000;
    var task = SomeOperationAsync();
    var completedTask = await Task.WhenAny(task, Task.Delay(timeout, cancelToken.Token));
    if (completedTask == task)
    {
        cancelToken.Cancel();
        await task;
    }
    else
    {
        // 超时处理
    }
}

可以给 Task 添加扩展方法,减少出现相同的代码

public static Task TimeoutAfter<TResult>(this Task<TResult> task,int TimeSpan timeout)
{
    using (var cancelToken = new CancellationTokenSource())
    {
        var completedTask = await Task.WhenAny(task, Task.Delay(timeout, cancelToken.Token));
        if (completedTask == task)
        {
            cancelToken.Cancel();
            return await task;
        }
        else
        {
            // 超时处理
        }
    }
}

原文:https://stackoverflow.com/questions/4238345/asynchronously-wait-for-taskt-to-complete-with-timeout