hello,咋们又见面啦,通过前面两篇文章的介绍,对task的创建、运行、阻塞、同步、延续操作等都有了很好的认识和使用,结合实际的场景介绍,这样一来在实际的工作中也能够解决很大一部分的关于多线程的业务,但是只有这一些是远远不够的,比如,比如,如果这么一个场景,当开启tsak异步任务后,有某个条件触发,需要终止tsak的执行又该如何实现呢?这一些问题正是我们今天需要交流分享的部分,带着这一些问题,咱们共同进入到今天的主题,谢谢!

在进入主题前,如果你没有阅读前面的两篇文章,欢迎您点击下面地址先阅读一下,这样能够更加连贯的掌握了解今天的内容,谢谢!

  第一篇:聊聊多线程哪一些事儿(task)之 一创建运行与阻塞

  第二篇:聊聊多线程哪一些事儿(task)之 二 延续操作

  第三篇:聊聊多线程哪一些事儿(task)之 三 异步取消和异步方法

Task之任务取消:CancellationTokenSource

关于线程取消,我相信大家在实际工作中都会遇到这样的问题,无论是采用哪一种方式实现异步线程,都会有相应的机制来取消线程操作。本次将同时对Thread的线程取消实现,Tsak的线程取消实现同时通过实例说明。

在我的工作经验中,需要取消异步线程作业的实际使用场景往往是一些异步作业程序,也就是一些周期性的,循环业务操作。比如周期性的数据同步、数据更新等等操作。比如:电商系统常见的一个场景,订单超时取消等等。

为了与前两篇的实例保持一致性,我现在还是以酒店平台的数据同步业务为例:

需求:每周三凌晨3点钟,通过携程提供的酒店分页查询接口,全量同步一次最新的酒店数据。并且能够通过人为的干预来终止数据同步操作。

下面我将分别通过Thread和task两种方式来实现

其一、Thread时代之任务取消

哈哈,实话实话说,在几年前的项目中,我也是采用Thread来实现异步线程的,也会遇到线程的取消的业务场景。我当时的实现方式是,定义一个全局变量,isStopThread(是否终止线程),去过需要取消任务,只需要控制isStopThread的值即可,每一次执行具体的业务时,首先判断一下isStopThread,只有非终止状态才执行具体的业务逻辑。 /// <summary> /// 携程 酒店数据同步作业(Thread) /// </summary>

 private static void CtripHoteDataSynchrByThread()
{
// CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
// 第一步通过thread开启一个线程
Thread thread = new Thread(() =>
{
// 获取数据的次数
int getDataIndex = 1;
isStopCtripHoteDataSynchr = false; // 通过调用携程的分页服务,获取其有效的酒店数据
// 在获取数据前,首先判断一下是否终止获取
       // while (!cancellationTokenSource.IsCancellationRequested)
 while (!isStopCtripHoteDataSynchr )
{
// 现在假设模拟,获取携程的所有有效的酒店数据通过 3 次就获取完毕
Console.WriteLine($"开始获取携程第 {getDataIndex} 页酒店数据....\n"); Thread.Sleep(3000);
Console.WriteLine($"携程第 {getDataIndex} 页酒店数据获取完毕\n");
getDataIndex++; // 模拟获取完第三页数据,代表数据获取完毕,直接终止掉
if (getDataIndex == 4)
{
Console.WriteLine($"同步完毕携程的所有酒店数据\n");
break;
}
} if (isStopCtripHoteDataSynchr)
{
Console.WriteLine($"取消同步携程酒店数据\n");
}
}); thread.Start(); Console.WriteLine("携程酒店数据同步中.....\n");
// 模拟实际数据同步中的取消操作
Console.WriteLine("如果需要取消数据同步,那么请输入任意字符即可取消操作\n"); Console.ReadLine(); // cancellationTokenSource.Cancel();
isStopCtripHoteDataSynchr = true; Console.WriteLine($"发起取消同步携程酒店数据请求\n");
}

执行结果:

通过测试结果我们可以看到,在获取第2页数据时,此时发起了一个取消线程命令,当第二页数据获取完毕后,线程就里面终止了,从而到达了线程取消的目的。

其二、Task时代之任务取消

随着Task的推出,微软也推出了一个专门服务于线程取消的帮助类(CancellationTokenSource),通过该类能够很好的帮助我们取消一个线程,话不多说,我们先通过CancellationTokenSource类实现上面示例的功能。

/// <summary>
/// 携程 酒店数据同步作业(Task)
/// </summary>
private static void CtripHoteDataSynchrByTask()
{
// 定义任务取消机制
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); // 第一步通过thread开启一个线程
Task thread = new Task(() =>
{
// 获取数据的次数
int getDataIndex = 1; // 通过调用携程的分页服务,获取其有效的酒店数据
// 在获取数据前,首先判断一下是否终止获取 while (!cancellationTokenSource.IsCancellationRequested)
{
// 现在假设模拟,获取携程的所有有效的酒店数据通过 3 次就获取完毕
Console.WriteLine($"开始获取携程第 {getDataIndex} 页酒店数据....\n"); Console.WriteLine($"携程第 {getDataIndex} 页酒店数据获取完毕\n");
getDataIndex++; // 模拟获取完第三页数据,代表数据获取完毕,直接终止掉
if (getDataIndex == 4)
{
Console.WriteLine($"同步完毕携程的所有酒店数据\n");
break;
}
} if (cancellationTokenSource.IsCancellationRequested)
{
Console.WriteLine($"取消同步携程酒店数据\n");
}
});
thread.Start(); Console.WriteLine("携程酒店数据同步中.....\n");
// 模拟实际数据同步中的取消操作
Console.WriteLine("如果需要取消数据同步,那么请输入任意字符即可取消操作\n"); Console.ReadLine(); // 直接取消线程
cancellationTokenSource.Cancel(); // 在指定时间后取消线程
// cancellationTokenSource.CancelAfter(1000); Console.WriteLine($"发起取消同步携程酒店数据请求\n");
}
 

测试结果:

通过测试结果,两种实现方式的结果完全一致

当然,CancellationTokenSource 还提供了CancelAfter(多久后取消)方法,来实现多久后取消线程。

说到这儿,不知道大家有没有发现一个问题CancellationTokenSource 其实现是不是与Task和Thread没有多少关系,在第一个实例中通过Thread实现的线程取消,同样可以结合CancellationTokenSource 来实现。所以说,在开始我说CancellationTokenSource 是微软提供的一个线程取消的一个帮助类就是这个原因。其实我可以打开CancellationTokenSource 的实现源码,其实我们就会一目了然,其取消线程的核心逻辑和我们上面的说Thread取消的原理很类似,都是控制一个变量的值来实现,只是CancellationTokenSource 对其所有操作进行了一个封装。其中的CancelAfter里面是开启了一个定义器,定时器的最终实现还是和Canel一样。如果想看CancellationTokenSource的源码,大家可以查看下面地址:https://www.cnblogs.com/majiang/p/7920102.html

最后需要说明的是Task与CancellationTokenSource都是.net Framework4.0+、.NET Core、.NET Standard。

异步方法之:(async/await)

c#5.0微软推出了一个新的特性那就是异步方法,其关键词为async。有了async我们要实现一个异步方法就简单的多啦,你会发现和实现一个同步方法很相似,只需要对方法加以async修饰即可。当然如果只是简单的修饰调用,那么也会是同步调用,为了达到真正的异步调用,往往是需要另外一个关键词await来配合使用。

先简单介绍一下async异步函数:

async的三种返回类型:

Tsak:其主要适用场景是,主程序只关心异步方法执行状态,不需要和主线程有任何执行结果数据交互。

Task<T>:其主要适用场景是,主程序不仅仅关心异步方法执行状态,并且还希望执行后返回一个数据类型为T的结果

void: 主程序既不关系异步方法执行状态,也不关心其执行结果,只是主程序调用一次异步方法,对于除事件处理程序以外的代码,通常不鼓励使用 async void 方法,因为调用方不能

  在介绍一下await关键词:

await其顾名思义就是等待的意思,其运行原理就是:调用方执行到await时就会立即返回,但是异步方法等待异步执行结果。所以await只能存在于async修饰的异步方法体中,await不阻塞主线程,只是阻塞当前异步方法继续往下执行,这样就能够达到真正异步的目的。

下面以一个简单的例子来说明一下每一种情况的使用:

static void Main(string[] args)
{
Console.WriteLine("主线程开始\n");
Console.WriteLine("主线程调用同步方法:SynTest\n");
SynTest(); Console.WriteLine("主线程调用异步方法:AsyncTestNoAwait\n");
AsyncTestNoAwait(); Console.WriteLine("主线程调用异步方法:AsyncTestHasAwait\n");
AsyncTestHasAwait(); Console.WriteLine("主线程结束\n");
Console.ReadKey();
} /// <summary>
/// 同步方法测试
/// </summary>
public static void SynTest()
{
Console.WriteLine("同步方法SynTest开始运行\n");
Thread.Sleep(5000);
Console.WriteLine("同步方法SynTest运行结束\n");
} /// <summary>
/// 异步方法测试(不带有 await关键词)
/// </summary>
public static async void AsyncTestNoAwait()
{
Console.WriteLine("异步方法AsyncTestNoAwait开始运行\n");
Thread.Sleep(5000);
Console.WriteLine("异步方法AsyncTestNoAwait运行结束\n");
} /// <summary>
/// 异步方法测试(带有 await关键词)
/// </summary>
public static async void AsyncTestHasAwait()
{
Console.WriteLine("异步方法AsyncTestHasAwait开始运行\n");
await Task.Delay(5000);
Console.WriteLine("异步方法AsyncTestHasAwait运行结束\n");
}

运行结果:

从运行结果我们可以很好的得出:

1、异步方法async如果没有await关键词,其执行原理还是同步调用

2、await关键词只能存在云async修饰的方法体中

3、异步方法async在调用时,只有遇到await关键词后的程序块才是异步执行,其await关键词前的代码块还是同步执行

好了,管理async先介绍到这儿,由于时间和文章篇幅原因,就不在详细介绍,里面还有很多内容需要注意,后续在根据实际做一个async/await的专题文章。

总结:

到目前为止,有关Task的3篇文章都到此结束,下面在回顾总结一下Task的相关功能点吧!

1、Task的创建运行可以有三种方式:new Task/Task.Factory/Task.Run

2、Task的返回参数定义Task<返回类型>

获取返回值:Task.Result->要阻塞主流程

3、Task线程的同步实现不仅仅可以通过RunSynchronously来实现同步运行,当然还可以通过Task.Result/Task.Wait等方式来变向实现

4、Task的wait/waitAll/waitAny实现阻塞等待执行结果

5、Task的WhenAny、WhenAll、ContinueWith实现延续操作

6、CancellationTokenSource实现异步任务取消

7、异步方法之:(async/await)实现同步和异步调用等

猜您喜欢:

 第一篇:聊聊多线程哪一些事儿(task)之 一创建运行与阻塞

 第二篇:聊聊多线程哪一些事儿(task)之 二 延续操作

END
为了更高的交流,欢迎大家关注我的公众号,扫描下面二维码即可关注,谢谢:

isStopCtripHoteDataSynchr 

聊聊多线程那一些事儿(task)之 三 异步取消和异步方法的更多相关文章

  1. 聊聊多线程哪一些事儿(task)之 三 异步取消和异步方法

    hello,咋们又见面啦,通过前面两篇文章的介绍,对task的创建.运行.阻塞.同步.延续操作等都有了很好的认识和使用,结合实际的场景介绍,这样一来在实际的工作中也能够解决很大一部分的关于多线程的业务 ...

  2. 聊聊多线程哪一些事儿(task)之 一

    多线程,一个多么熟悉的词汇,作为一名程序员,我相信无论是从事什么开发语言,都能够轻轻松松说出几种实现多线程的方式,并且在实际工作种也一定用到过多线程,比如:定时器.异步作业等等,如果你说你没有用过多线 ...

  3. 聊聊多线程哪一些事儿(task)之 二 延续操作

    hello,又见面啦,昨天我们简单的介绍了如何去创建和运行一个task.如何实现task的同步执行.如何阻塞等待task集合的执行完毕等待,昨天讲的是task的最基本的知识点,如果你没有看昨天的博客, ...

  4. 聊聊多线程那一些事儿 之 五 async.await深度剖析

     hello task,咱们又见面啦!!是不是觉得很熟读的开场白,哈哈你哟这感觉那就对了,说明你已经阅读过了我总结的前面4篇关于task的文章,谢谢支持!感觉不熟悉的也没有关系,在文章末尾我会列出前四 ...

  5. 聊聊RabbitMQ那一些事儿之一基础应用

    聊聊RabbitMQ那一些事儿之一基础应用 Hi,各位热爱技术的小伙伴您们好,今年的疫情害人啊,真心祝愿您和您的家人大家都平平安安,健健康康.年前到现在一直没有总结点东西,写点东西,不然久了自己感觉自 ...

  6. 异步编程系列06章 以Task为基础的异步模式(TAP)

    p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提 ...

  7. SpringBoot整合全局异常处理&SpringBoot整合定时任务Task&SpringBoot整合异步任务

    ============整合全局异常=========== 1.整合web访问的全局异常 如果不做全局异常处理直接访问如果报错,页面会报错500错误,对于界面的显示非常不友好,因此需要做处理. 全局异 ...

  8. C#.NET使用Task,await,async,异步执行控件耗时事件(event),不阻塞UI线程和不跨线程执行UI更新,以及其他方式比较

    使用Task,await,async,异步执行事件(event),不阻塞UI线程和不跨线程执行UI更新 使用Task,await,async 的异步模式 去执行事件(event) 解决不阻塞UI线程和 ...

  9. .Net Core WebAPI 基于Task的同步&异步编程快速入门

    .Net Core WebAPI 基于Task的同步&异步编程快速入门 Task.Result async & await 总结 并行任务(Task)以及基于Task的异步编程(asy ...

随机推荐

  1. java基础部分的一些有意思的东西。

    ${li.key!=''&&li.key!= null}可以直接判断不为空 ${empty li.value}也是不为空. 最近好烦迭代map里的map或者map里的list 后来发现 ...

  2. 复杂SQL示例 (排行榜需求)

    公司项目要求做出排行榜,根据六组数据依次排行,关联多表,SQL记录下来方便日后查看 " ?><!DOCTYPE mapper PUBLIC "-//mybatis.or ...

  3. KiCad Mark 点名称

    KiCad Mark 点名称 Mark 点的用处是给 IC 等高密度的元件在贴片时定位参考.

  4. qt中窗口绘制——图片的绘制

    在qt 中,QPixmap 用于表示一张图片,支持png,jpg格式的加载. QPixmap pm("c:/test.png"); 或者 QPixmap pm; pm.load(& ...

  5. et al.

    et al.   英 [ˌet ˈæl]   adv. <拉>以及其他人; [例句]Earlier research in conventional RCS modelling for d ...

  6. NSDate 格式化含有毫秒

    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"]; 版权声明:本文为博主原创文章,未经博主允许不得转载.

  7. AtCoder Beginner Contest 078 D ABS

    光做C了,做完C,就要结束了,看了看D,没看懂那操作啥意思,就扔了. 刚才看了看,突然懂了.. 就是每个人从那堆牌上边拿牌,最少拿一张,最多可以全拿走,然后手里留下最后一张拿到的,其余的都扔掉. 比如 ...

  8. ip地址库 与浏览器的关系

    https://zhidao.baidu.com/question/325152705.html 只要手机连接数据上网就会产生ip,只要进入了淘宝,就能查出用户访问记录的. 手机是运营商动态分配的.它 ...

  9. HDU 2844 混合背包、

    题意:一个人想买手表,给你n个价值的硬币,然后给你n个价值硬币对应的个数.但是呢,这个人只知道这个手表的价格不超过m元.问他最多能买多少种价值的手表 思路:dp背包专题 但是- - 一直不知道该怎么d ...

  10. 2003年NOIP普及组复赛题解

    题目涉及算法: 乒乓球:简单字符串模拟: 数字游戏:区间DP: 栈:卡特兰数 麦森数:高精度.快速幂.数学. 乒乓球 题目链接:https://www.luogu.org/problem/P1042 ...