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. Spring集成Hessian1

    Hessian是一个轻量级的远程调用工具,采用的是Binary RPC协议,很适合于发送二进制数据,基于HTTP具有防火墙穿透能力.Hessian一般是通过Web应用来提供服务,因此非常类似于平时我们 ...

  2. 读取Excel文件的两种方法比较 以及用NPOI写入Excel

    1. 采用NPOI方式,只需引用NPOI.dll,但目前最高只能到2.4.0版. 缺点:只支持.xls,不支持.xlsx格式.github上的2.4.1版支持.xlsx,但总提示缺ICSharpCod ...

  3. iOS runtime整理

    iOS利用Runtime自定义控制器POP手势动画 http://www.cocoachina.com/ios/20150401/11459.html  Objective C运行时(runtime) ...

  4. 快速完成智能数据构建,Dataphin公共云版本全面解读

    公测两个月,Dataphin公共云版本已经受到了阿里云上众多轻量级用户的关注.事实上,Dataphin作为一款大数据智能构建与管理的产品,其核心功能是面向各行各业大数据建设.管理及应用诉求,一站式提供 ...

  5. Python collections的使用

    collections是Python内建的一个集合模块,提供了许多有用的集合类. 本文将介绍以下几种方法: namedtuple Counter() deque OrderedDict 一.named ...

  6. JSON解析的成长史——原来还可以这么简单

    本文系统介绍,JSON解析的成长史,未经允许,禁止转载. JSON是一种轻量级的数据格式,一般用于数据交互 Android交互数据主要有两种方式:Json和Xml,Xml格式的数据量要比Json格式略 ...

  7. @atcoder - Japanese Student Championship 2019 Qualification - F@ Candy Retribution

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 请找到满足以下条件的长度为 N 的非负整数序列 A1, A2, ...

  8. css半透明渐变过渡效果

    效果图: 代码如下: background-image: -webkit-gradient(linear,left top, left bottom,from(rgba(255,255,255,0)) ...

  9. PHP会话技术

    由于HTTP协议是无连接.无状态的,所以HTTP协议无法记住客户端的信息.为了弥补HTTP协议的这两种不足,所以出现了会话技术. 1 Cookie技术 1.1 什么是Cookie 服务器端,将能够唯一 ...

  10. [全+转载] solaris 网络配置

    ===================== 较为重要的几个文件: /etc/nodename                      主机名(即 hostname命令的输出) /etc/defaul ...