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

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

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


C# Task 实现任务超时取消、超时取消然后重试 超过重试最大次数就结束。的更多相关文章
- C# CancellationTokenSource 终止线程 CancellationTokenSource实现对超时任务的取消
C# 使用 CancellationTokenSource 终止线程 使用CancellationTokenSource对象需要与Task对象进行配合使用,Task会对当前运行的状态进行控制(这个不用 ...
- Java_InvokeAll_又返回值_多个线程同时执行,取消超时线程
package com.demo.test4; import java.util.ArrayList; import java.util.List; import java.util.concurre ...
- .NET 异步多线程,Thread,ThreadPool,Task,Parallel,异常处理,线程取消
今天记录一下异步多线程的进阶历史,以及简单的使用方法 主要还是以Task,Parallel为主,毕竟用的比较多的现在就是这些了,再往前去的,除非是老项目,不然真的应该是挺少了,大概有个概念,就当了解一 ...
- .NET异步多线程,Thread,ThreadPool,Task,Parallel,异常处理,线程取消
今天记录一下异步多线程的进阶历史,以及简单的使用方法 主要还是以Task,Parallel为主,毕竟用的比较多的现在就是这些了,再往前去的,除非是老项目,不然真的应该是挺少了,大概有个概念,就当了解一 ...
- 【3】JMicro微服务-服务超时,重试,重试间隔
如非授权,禁止用于商业用途,转载请注明出处作者:mynewworldyyl 接下来的内容都基于[2]JMicro微服务-Hello World做Demo 微服务中,超时和重试是一个最基本问题下面Dem ...
- zookeeper会话超时 链接超时的排查
1.会话概述 在ZooKeeper中,客户端和服务端建立连接后,会话随之建立,生成一个全局唯一的会话ID(Session ID).服务器和客户端之间维持的是一个长连接,在SESSION_TIMEOUT ...
- session超时设置+超时页面跳转
session超时设置,方法有三种: (1)在主页面或者公共页面中加入:session.setMaxInactiveInterval(600);参数600单位是秒,即在没有10分钟活动后,sessio ...
- APP请求超时问题-ios超时-android超时
最近发现公司的app在高峰期超时严重.用wifi网络一直超时,但qq等却正常.换成手机卡网络正常. 起初以为是DNS解析问题. 后来抓包,发现DNS解析正常,可以得到正确的A记录. 但tcp retr ...
- 分布式事务框架.NetCore CAP总结
来自CAP原作者yang-xiaodong的原理图: 本文撰写者:cmliu,部分内容引用自官方文档,部分内容待更新# .NetCore CAP # 1,简介 CAP 是一个遵循 .NET Stand ...
- 使用C# HttpWebRequest进行多线程网页提交。Async httpclient/HttpWebRequest实现批量任务的发布及异步提交和超时取消
使用线程池并发处理request请求及错误重试,使用委托处理UI界面输出. http://www.cnblogs.com/Charltsing/p/httpwebrequest.html for (i ...
随机推荐
- day05-优惠券秒杀01
功能03-优惠券秒杀01 4.功能03-优惠券秒杀 4.1全局唯一ID 4.1.1全局ID生成器 每个店铺都可以发布优惠券: 当用户抢购时,就会生成订单,并保存到tb_voucher_order这张表 ...
- java POI创建HSSFWorkbook工作簿
1. POI Apache POI 是基于 Office Open XML 标准(OOXML)和 Microsoft 的 OLE 2 复合文档格式(OLE2)处理各种文件格式的开源项目. 2. 样式设 ...
- Amazon S3 对象存储Java API操作记录(Minio与S3 SDK两种实现)
缘起 今年(2023年) 2月的时候做了个适配Amazon S3对象存储接口的需求,由于4月份自学考试临近,一直在备考就拖着没总结记录下,开发联调过程中也出现过一些奇葩的问题,最近人刚从考试缓过来顺手 ...
- Lucas定理——定义、证明、实现、运用
目录 什么是Lucas定理 证明Lucas定理 Lucas定理求解组合数的C++实现 什么是Lucas定理 这是一个有助于分解组合数来求解的定理,适合模数小,数字大的问题. 有质数 \(p\),对于\ ...
- 分享Zeal的全套离线文档
鉴于Zeal自身的下载速度... 为了方便大家,现在把我自己下载好的Zeal离线文档全部分享出来 百度网盘链接:https://pan.baidu.com/s/19WeEWij3evnuMWhzbHu ...
- git仓库过渡,同时向两个仓库推送代码
公司部门被大佬收购,产品项目迁移新公司仓库,过渡期间产品上线流程继续使用原公司的,新公司部署新系统后通过域名重定向逐渐将用户引流到新系统上完成切换,最后关闭原公司系统及上线流程. 过渡期间新功能代码需 ...
- 2022-03-04:爱吃香蕉的珂珂。 珂珂喜欢吃香蕉。这里有 N 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 H 小时后回来。 珂珂可以决定她吃香蕉的速度 K (单位:根
2022-03-04:爱吃香蕉的珂珂. 珂珂喜欢吃香蕉.这里有 N 堆香蕉,第 i 堆中有 piles[i] 根香蕉.警卫已经离开了,将在 H 小时后回来. 珂珂可以决定她吃香蕉的速度 K (单位:根 ...
- vue全家桶进阶之路9:常用指令
以下是一些常见的指令: v-bind - 用于绑定一个或多个属性到组件或 HTML 元素上. v-model - 用于双向绑定一个表单元素或组件的值到数据模型上. v-for - 用于循环遍历一个数组 ...
- 啊哈C语言案例学习笔记
Hello World #include<stdio.h> /* 技术要点: 初学者在编写程序时,经常会忘记在语句后边添加分号, */ int main() { printf(" ...
- RoCE多网卡时,报文可以过去,但是回不来
摘要:虽然网卡是接入RoCE网络,但其实问题本身是单纯路由相关的,所以看的时候,不用关注RoCE,只当做一个独立子网就行了 本文分享自华为云社区<<跟唐老师学习云网络> - RoCE ...