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

  • C# Task 实现任务超时取消、超时取消然后重试 超过重试最大次数就结束。已关闭评论
  • 182 次浏览
  • A+
所属分类:.NET技术

任务超时取消 示例

        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 实现任务超时取消、超时取消然后重试 超过重试最大次数就结束。