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!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值