C# Task 实现任务超时取消、超时取消然后重试 超过重试最大次数就结束。

在C#中,我们可以使用Task类来实现任务超时取消、超时取消然后重试的功能。当一个任务超过指定的重试次数后,程序将自动结束。下面我们将详细介绍如何使用Task类和CancellationTokenSource类来实现这个功能。

首先,我们需要创建一个CancellationTokenSource对象,它用于管理任务的取消操作。我们可以通过调用CancellationTokenSource的构造函数来创建一个新的CancellationTokenSource对象,并传入一个布尔值参数,表示是否立即启动取消操作。.

        public static async Task TimeoutCancelTask()        {            CancellationTokenSource cts = new CancellationTokenSource();//取消令牌            Task task = DoAction(cts);//业务异步任务            double timeoutSeconds = 2;//超时时间 秒            Task delayTask = Task.Delay(TimeSpan.FromSeconds(timeoutSeconds));//指定一个等待任务 等待到超时时间            Task completeTask = await Task.WhenAny(task, delayTask);//等待两个任务,任意一个任务执行完成。返回率先完成的任务            if (completeTask == delayTask)//如果率先完成的是超时等待任务,就说明业务任务执行超时了。            {                cts.Cancel();//取消令牌 状态改为取消                Console.WriteLine("任务已超时取消");            }            else            {                Console.WriteLine("任务已完成");            }        }
        //模拟业务任务        public static async Task DoAction(CancellationTokenSource cts)        {            await Task.Delay(200);            for (int i = 1; i <= 5; i++)            {                if (cts.IsCancellationRequested)//在业务任务每个耗时的操作开始之前判断取消令牌是否已取消                    break;                Console.WriteLine(i);                await Task.Delay(TimeSpan.FromSeconds(1));//模拟业务操作,耗时任务。            }        }

封装一个帮助方法

  public static class TaskExtensions    {        /// <summary>        /// 任务超时取消        /// </summary>        /// <param name="func">业务任务(超时要取消任务的话 需要在耗时操作之前 判断cts如果取消就结束方法)</param>        /// <param name="timeoutSeconds">超时时间 秒</param>        /// <param name="cts">任务取消令牌</param>        /// <returns>true执行成功 false超时取消</returns>        public static async Task<bool> TimeoutCancelAsync(            Func<CancellationTokenSource, Task> func, double timeoutSeconds, CancellationTokenSource cts)        {            Task task = func.Invoke(cts);            Task delayTask = Task.Delay(TimeSpan.FromSeconds(timeoutSeconds), cts.Token);            Task completeTask = await Task.WhenAny(task, delayTask);            if (completeTask == task)                return true;            cts.Cancel();            Console.WriteLine("【TimeoutCancelAsync】任务执行超时已取消。");            return false;        }
        /// <summary>        /// 任务超时取消 (带泛型返回值)        /// </summary>        /// <param name="func">业务任务带返回值(超时要取消任务的话 需要在耗时操作之前 判断cts如果取消就结束方法)</param>        /// <param name="timeoutSeconds">超时时间 秒</param>        /// <param name="cts">任务取消令牌</param>        /// <returns>IsSuccess:true执行成功 false超时取消  Result:任务执行成功的结果</returns>        public static async Task<(bool IsSuccess, T Result)> TimeoutCancelAsync<T>(            Func<CancellationTokenSource, Task<T>> func, double timeoutSeconds, CancellationTokenSource cts)        {            Task<T> task = func.Invoke(cts);            Task<T> delayTask = Task.Delay(TimeSpan.FromSeconds(timeoutSeconds), cts.Token)                    .ContinueWith(_ => default(T));            Task completeTask = await Task.WhenAny<T>(task, delayTask);            if (completeTask == task)                return (true, task.Result);            cts.Cancel();            Console.WriteLine("【TimeoutCancelAsync】任务执行超时已取消。");            return (false, delayTask.Result);        }

        /// <summary>        /// 任务超时取消 然后重新执行        /// </summary>        /// <param name="func">业务任务(超时要取消任务的话 需要在耗时操作之前 判断cts如果取消就结束方法)</param>        /// <param name="timeoutSeconds">超时时间 秒</param>        /// <param name="maxRetryCount">最大重试次数</param>        /// <param name="cts">任务取消令牌</param>        /// <returns>是否成功</returns>        public static async Task<bool> TimeoutRetryAsync(            Func<CancellationTokenSource, Task> func, double timeoutSeconds, int maxRetryCount, CancellationTokenSource cts)        {            for (int i = 0; i <= maxRetryCount; i++)            {                if (cts.IsCancellationRequested)                    break;                if (i > 0)                    Console.WriteLine($"【TimeoutRetryAsync】任务第{i}次重试开始...");                CancellationTokenSource currentCts = CancellationTokenSource.CreateLinkedTokenSource(cts.Token);                Task task = func.Invoke(currentCts);                Task delayTask = Task.Delay(TimeSpan.FromSeconds(timeoutSeconds), currentCts.Token);                Task completeTask = await Task.WhenAny(task, delayTask);                if (completeTask == task)                {                    currentCts.Dispose();                    return true;                }                currentCts.Cancel();                Console.WriteLine("【TimeoutRetryAsync】任务执行超时已取消。");            }            return false;        }
        /// <summary>        /// 任务超时取消 然后重新执行 (带泛型返回值)        /// </summary>        /// <param name="func">业务任务带返回值(超时要取消任务的话 需要在耗时操作之前 判断cts如果取消就结束方法)</param>        /// <param name="timeoutSeconds">超时时间 秒</param>        /// <param name="maxRetryCount">最大重试次数</param>        /// <param name="cts">任务取消令牌</param>        /// <returns>IsSuccess:是否成功  Result:任务执行成功的结果</returns>        public static async Task<(bool IsSuccess, T Result)> TimeoutRetryAsync<T>(            Func<CancellationTokenSource, Task<T>> func, double timeoutSeconds, int maxRetryCount, CancellationTokenSource cts)        {            for (int i = 0; i <= maxRetryCount; i++)            {                if (cts.IsCancellationRequested)                    break;                if (i > 0)                    Console.WriteLine($"【TimeoutRetryAsync】任务第{i}次重试开始...");                CancellationTokenSource currentCts = CancellationTokenSource.CreateLinkedTokenSource(cts.Token);                Task<T> task = func.Invoke(currentCts);                Task<T> delayTask = Task.Delay(TimeSpan.FromSeconds(timeoutSeconds), currentCts.Token)                    .ContinueWith(_ => default(T));                Task completeTask = await Task.WhenAny<T>(task, delayTask);                if (completeTask == task)                {                    currentCts.Dispose();                    return (true, await task);                }                currentCts.Cancel();                Console.WriteLine("【TimeoutRetryAsync】任务执行超时已取消。");            }            return (false, default(T));        }    }

测试用例:

        public static async Task Go()        {            double timeoutSeconds = 2;//超时时间 秒            int maxRetryCount = 2;//最大重试次数            CancellationTokenSource cts = new CancellationTokenSource();            bool isSuccess = false;            string result = string.Empty;            //1.超时取消任务 无返回值            //isSuccess = await TaskExtensions.TimeoutCancelAsync((cts) => DoActionNoResult(cts), timeoutSeconds, cts);
            //1.超时取消任务 无返回值            //(isSuccess, result) = await TaskExtensions.TimeoutCancelAsync((cts) => DoActionWithResult(cts), timeoutSeconds, cts);
            //3.超时取消并重试任务 无返回值            //isSuccess = await TaskExtensions.TimeoutRetryAsync((cts) => DoActionNoResult(cts), timeoutSeconds, maxRetryCount, cts);
            //4.超时取消并重试任务 带返回值任务            (isSuccess, result) = await TaskExtensions.TimeoutRetryAsync((cts) => DoActionWithResult(cts), timeoutSeconds, maxRetryCount, cts);                        if(isSuccess)             {                Console.WriteLine("任务执行成功,结果:" + result);            }            else            {                Console.WriteLine("任务执行失败!");            }            Console.ReadLine();        }
        public static async Task DoActionNoResult(CancellationTokenSource cts)        {            await Task.Delay(200);            for (int i = 1; i <= 5; i++)            {                if (cts.IsCancellationRequested)//在业务任务每个耗时的操作开始之前判断取消令牌是否已取消                    return;                Console.WriteLine($"num:{i}");                await Task.Delay(1000);//模拟业务操作,耗时任务。            }        }
        public static async Task<string> DoActionWithResult(CancellationTokenSource cts)        {            await Task.Delay(200);            for (int i = 1; i <= 5; i++)            {                if (cts.IsCancellationRequested)//在业务任务每个耗时的操作开始之前判断取消令牌是否已取消                    return "";                Console.WriteLine($"num:{i}");                await Task.Delay(1000);//模拟业务操作,耗时任务。            }            return "666";        }

案例4-1

double timeoutSeconds = 2;//超时时间 秒int maxRetryCount = 2;//最大重试次数 //业务方法运行时间为5.3秒左右,会一直超时 重试2次后结束

C# Task 实现任务超时取消、超时取消然后重试 超过重试最大次数就结束。

案例4-2

double timeoutSeconds = 6;//超时时间 秒int maxRetryCount = 2;//最大重试次数 //业务方法运行时间为5.3秒左右,不会超时,会执行成功并返回结果

C# Task 实现任务超时取消、超时取消然后重试 超过重试最大次数就结束。

案例4-3

double timeoutSeconds = i+4;//超时时间 秒int maxRetryCount = 2;//最大重试次数 //业务方法运行时间为5.3秒左右,将超时时间设置为(当前重试次数+4)。前两次执行会超时,第三次执行成功并返回结果

C# Task 实现任务超时取消、超时取消然后重试 超过重试最大次数就结束。

C# Task 实现任务超时取消、超时取消然后重试 超过重试最大次数就结束。