C# 方法执行超时策略
使用Task的等待机制来实现。
同步方法使用Task的实例方法wait() 设置执行等待时长;
异步方法则用Task.WhenAny()方法,与delay等待做比较;
注意:等待超时后,只是返回了默认值,实际调用的方法并未中断(即执行原方法的线程仍在执行,.NET中不能强制终止正在执行的线程),一定要注意确保数据唯一性。比如数据同步接口,方法内功能:【推送某个状态给其他系统成功后,再更新本地数据库标识】,如果该方法有超时策略,方法超时返回默认值时,程序并不清楚该方法是否执行成功(超时不代表失败)。如果是循环执行的线程,可以使用cts.Token.IsCancellationRequested来退出。
using System;
using System.Threading;
using System.Threading.Tasks;namespace AspCoreWebApiTest.Common
{public class OverTimeHandler{/// <summary>/// 同步执行超时熔断/// </summary>/// <typeparam name="T">返参类型</typeparam>/// <param name="action">同步方法</param>/// <param name="timeSpan">等待时长</param>/// <param name="defaultValue">默认值</param>/// <returns></returns>public static T Excute<T>(Func<T> action, TimeSpan timeSpan, T defaultValue = default){var cts = new CancellationTokenSource();var task = Task.Run(action, cts.Token);if (task.Wait(timeSpan)){return task.Result;}else{cts.Cancel();System.Diagnostics.Debug.WriteLine($"{DateTime.Now} 同步方法【{action.Method.Name}】执行超时!");return defaultValue;}}/// <summary>/// 异步执行超时熔断/// </summary>/// <typeparam name="T">返参类型</typeparam>/// <param name="action">异步方法</param>/// <param name="timeSpan">等待时长</param>/// <param name="defaultValue">默认值</param>/// <returns></returns>public static async Task<T> ExcuteAsync<T>(Func<Task<T>> action, TimeSpan timeSpan, T defaultValue = default){var cts = new CancellationTokenSource();var task = action();var delayTask = Task.Delay(timeSpan, cts.Token);var completeTask = await Task.WhenAny(task, delayTask);if (completeTask == task){cts.Cancel(); // 取消延迟任务return await task;}else{cts.Cancel(); // 取消原始任务System.Diagnostics.Debug.WriteLine($"{DateTime.Now} 异步方法【{action.Method.Name}】执行超时!");return defaultValue;}}}
}
调用示例
public async Task<string> Test(int num)
{TimeSpan ts1 = TimeSpan.FromSeconds(num);string result = OverTimeHandler.Excute(Sleep, ts1, $"{DateTime.Now} Sleep OverTime!!!");result += await OverTimeHandler.ExcuteAsync(SleepAsync, ts1, $"{DateTime.Now} SleepAsync OverTime!!!");return result;
}
private string Sleep()
{Thread.Sleep(TimeSpan.FromSeconds(3));System.Diagnostics.Debug.WriteLine($"{DateTime.Now} Sleep finished!");return "Sleep finished!";
}
private async Task<string> SleepAsync()
{await Task.Delay(TimeSpan.FromSeconds(5));System.Diagnostics.Debug.WriteLine($"{DateTime.Now} SleepAsync finished!");return "SleepAsync finished!";
}
结果:
Test方法入参:2
返参:2025/7/24 16:50:23 Sleep OverTime!!!2025/7/24 16:50:25 SleepAsync OverTime!!!
日志:
2025/7/24 16:50:25 同步方法【Sleep】执行超时!
2025/7/24 16:50:26 Sleep finished!
2025/7/24 16:50:27 异步方法【SleepAsync】执行超时!
2025/7/24 16:50:30 SleepAsync finished!
Test方法入参:4
返参:Sleep finished!2025/7/24 16:52:47 SleepAsync OverTime!!!
日志:
2025/7/24 16:52:47 Sleep finished!
2025/7/24 16:52:51 异步方法【SleepAsync】执行超时!
2025/7/24 16:52:52 SleepAsync finished!
Test方法入参:6
返参:Sleep finished!SleepAsync finished!
日志:
2025/7/24 16:54:18 Sleep finished!
2025/7/24 16:54:23 SleepAsync finished!