C# 为异步函数实现WaitAsync方法
从 .NET 6 开始,System.Threading.Tasks.Task类 原生提供了 WaitAsync方法,该方法可以很方便的为任意异步函数提供超时功能。但是Framework没有该方法。不过我们可以通过Task.WhenAny方法可以实现类似的功能 。
- 无返回值
csharp
/// <summary>
/// 异步等待任务完成,支持超时
/// </summary>
/// <param name="task">要等待的任务</param>
/// <param name="timeoutMilliseconds">超时时间(毫秒)</param>
/// <returns>任务本身</returns>
public static async Task WaitAsync(this Task task, int timeout)
{
if (task == null)
throw new ArgumentNullException(nameof(task));
if (task.IsCompleted)
return;
using (CancellationTokenSource cts = new CancellationTokenSource())
{
Task completedTask = await Task.WhenAny(task, Task.Delay(timeout, cts.Token)).ConfigureAwait(false);
if (completedTask != task)
throw new TimeoutException($"等待任务超时({timeout} 毫秒)");
cts.Cancel();
await task.ConfigureAwait(false);
}
}
- 有返回值
csharp
/// <summary>
/// 异步等待一个 Task<T> 完成,并获取结果,支持超时
/// </summary>
/// <typeparam name="T">任务返回的数据类型</typeparam>
/// <param name="task">要等待的任务</param>
/// <param name="timeoutMilliseconds">超时时间(毫秒)</param>
/// <returns>任务的结果 T</returns>
public static async Task<T> WaitAsync<T>(this Task<T> task, int timeout)
{
if (task == null)
throw new ArgumentNullException(nameof(task));
if (task.IsCompleted)
return task.Result;
using (CancellationTokenSource cts = new CancellationTokenSource())
{
Task completedTask = await Task.WhenAny(task, Task.Delay(timeout, cts.Token)).ConfigureAwait(false);
if (completedTask != task)
throw new TimeoutException($"等待任务超时({timeout} 毫秒)");
cts.Cancel();
return await task.ConfigureAwait(false);
}
}