使用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!
1195

被折叠的 条评论
为什么被折叠?



