C#多线程编程(3)--开启子任务
上一篇我讲解了await和async关键字,这两个关键字的作用是将async限定的方法中await关键字后面的部分封装成一个委托,该委托会在await修饰的Task完成后再执行。简单的说,就是等待任务完成后,后面的程序才执行,且该等待不会造成线程阻塞。关键是在任务执行完成后,程序会继续交给主线程执行。接下来,我来介绍在任务执行结束后,用新任务来执行方法。
废话不多上,上代码,我们来看看如何在任务结束后继续由线程池继续完成其他方法。
static void Main(string[] args)
{
RunAsync();
Console.WriteLine("Async Run");
Console.Read();
}
public static void RunAsync()
{
var task = Task.Run(() =>
{
Thread.Sleep();
return "task finished";
});
//当task完成后,会在由线程池继续执行
task.ContinueWith(t =>
{
Thread.Sleep();
Console.WriteLine(task.Result);
});
}
可以看到,RunAsync方法中并没有添加async和await关键字,但是运行程序后,主线程没有被阻塞。这是因为ContinueWith会将委托参数“挂”到线程池的任务队列中,该委托只有在task执行结束后,才会开始执行。ContinueWith方法会返回一个Task,该Task就是task执行结束后会开始执行的Task,该Task也是可以等待的。注意,ContinueWIth和await关键字的区别就在:await在任务完成后,会由主线程继续执行,但是ContinueWith中的方法会继续由线程池执行。
接下来,我们来了解一下,任务能否取消,以及取消后会发生什么。
C#提供的任务取消的方式是“协作式”取消,在构造任务时,需要先构造一个System.Threading.CancellationTaskSource对象,该对象看起来像这样
public sealed class CancellationTaskSource:IDisposable{
public CancellationTokenSource();
public void Dispose();//释放资源
public bool IsCancellationRequested{get;}
public CancellationToken Token{get;}
public void Cancel();//内部调用Cancel并传递false
public void Cancel(bool throwOnFirstException);
}
CancellationTaskSource对象中含有一个Token,它的类型是CancellationToken,这是一个轻量级值类型,它包含一个私有的对CancellationTaskSource的引用,当构造Task时,需要将这个Token传入,如下所示
static void Main(string[] args){
CancelTask();
Console.WriteLine("Async Run");
Console.Read();
}
public static void CancelTask()
{
//定时1000ms后自动取消任务
var cancelSource = new CancellationTokenSource();
Task.Run(() =>
{
//模拟其他任务
Thread.Sleep();
//如果取消请求已发送,则不会显示Task over
if (!cancelSource.IsCancellationRequested)
Console.WriteLine("Task over");
}, cancelSource.Token);
cancelSource.Token.Register(() => Console.WriteLine("Task cancel"));
}
运行后可以看到大约1秒后,控制台显示了Task cancel,并且在没有显示Task over。证明任务被取消了。Task.Run()方法的其中一个重载是接受一个CancelToken参数,我们传入的是cancelSource的Token,这表明cancelSource就可以控制Task的取消与否。我的做法是在1秒后自动取消任务,也可以手动调用cancelSource.Cancel()方法来显式取消任务。我在Token上订阅了取消的事件,在任务被取消后,执行我的方法,这里是控制台打印出Task cancel。也可以在任务中,利用“闭包”,将Token传入到任务中,如下
static void Main(string[] args){
CancelTask();
Console.WriteLine("Async Run");
Console.Read();
}
public static void CancelTask(){
var cancelSource = new CancellationTokenSource();
Task.Run(() =>{
int count = ;
for (int i = ; i < ; i++)
{
if (cancelSource.IsCancellationRequested)
break;
count+=i;
Thread.Sleep();
}
Console.WriteLine(count);
}, cancelSource.Token);
cancelSource.Token.Register(() => Console.WriteLine("Task cancel"));
}
手动取消有2个方法,一是cancelSource.Cancel(),另一个是cancelSource.CancelAfter(),示例如下
public static void CancelTask(){
var cancelSource = new CancellationTokenSource();
Task.Run(() =>
{
Thread.Sleep();
Console.WriteLine("Task over");
}, cancelSource.Token);
cancelSource.Token.Register(() => Console.WriteLine("Task cancel"));
//此处调用cancelSource.Cancel()的话会立即结束任务
//该方法会大约1秒后取消任务
cancelSource.CancelAfter();
}
该示例和上面的在构造函数中传入1000ms的延时是一样的效果,若调用Cancel(),则立刻结束任务。
以上就是本篇内容,介绍了Task.ContinueWith方法,以及如何取消任务。若文中不能满足你的要求,可以查看诸如Task.Run()或者Task.ContinueWith()方法的几个重载,还有其他的使用方法,本人并没有将全部细枝末节全部学会,主要的目的是掌握多线程的基本使用方法。《CLR via C#》书中也有很详细的讲解,我的这个系列就是从该书中提取,有兴趣的小伙伴可以看一看。欢迎有问题的和我在评论区交流。
下一篇,我给大家介绍一下C#并行的奇技淫巧:并行的For、Foreach循环以及PLINQ。
C#多线程编程(3)--开启子任务的更多相关文章
- Java多线程编程实战指南 设计模式 读书笔记
线程设计模式在按其有助于解决的多线程编程相关的问题可粗略分类如下. 不使用锁的情况下保证线程安全: Immutable Object(不可变对象)模式.Thread Specific Storage( ...
- Web Worker javascript多线程编程(二)
Web Worker javascript多线程编程(一)中提到有两种Web Worker:专用线程dedicated web worker,以及共享线程shared web worker.不过主要讲 ...
- 5天玩转C#并行和多线程编程 —— 第三天 认识和使用Task
5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...
- IOS高级编程之三:IOS 多线程编程
多线程的概念在各个操作系统上都会接触到,windows.Linux.mac os等等这些常用的操作系统,都支持多线程的概念. 当然ios中也不例外,但是线程的运行节点可能是我们平常不太注意的. 例如: ...
- Java多线程编程核心技术---Java多线程技能
基本概念 进程是操作系统结构的基础,是一次程序的执行,是一个程序及其数据结构在处理机上顺序执行时所发生的活动,是程序在一个数据集合上运行的过程,是系统进行资源分配和调度的独立单位.线程可以理解成是在进 ...
- iOS开发——多线程篇——NSOperation(基于GCD多线程编程),下载图片并合成新图片
一.NSOperation的基本概念1.简介NSOperation的作用配合使用NSOperation和NSOperationQueue也能实现多线程编程 NSOperation和NSOperatio ...
- 多线程编程1 - NSThread
每个iOS应用程序都有个专门用来更新显示UI界面.处理用户的触摸事件的主线程,因此不能将其他太耗时的操作放在主线程中执行,不然会造成主线程堵塞(出现卡机现象),带来极坏的用户体验.一般的解决方案就是将 ...
- Java多线程编程——进阶篇二
一.线程的交互 a.线程交互的基础知识 线程交互知识点需要从java.lang.Object的类的三个方法来学习: void notify() 唤醒在此对象监视器上等待的单个 ...
- android: 多线程编程基础
9.1 服务是什么 服务(Service)是 Android 中实现程序后台运行的解决方案,它非常适合用于去执行那 些不需要和用户交互而且还要求长期运行的任务.服务的运行不依赖于任何用户界面,即使 ...
- 深入HTML5 Web Worker应用实践:多线程编程
HTML5 中工作线程(Web Worker)简介 至 2008 年 W3C 制定出第一个 HTML5 草案开始,HTML5 承载了越来越多崭新的特性和功能.它不但强化了 Web 系统或网页的表现性能 ...
随机推荐
- 【模板小程序】求第n个fibonacci数
//fibonacci,find the nth num. 1 1 2 3 5 8... #include <iostream> using namespace std; int fib( ...
- 游戏服务器设计之NPC系统
游戏服务器设计之NPC系统 简介 NPC系统是游戏中非常重要的系统,设计的好坏很大程度上影响游戏的体验.NPC在游戏中有如下作用: 引导玩家体验游戏内容,一般游戏内有很多主线.支线任务,而任务的介绍. ...
- 记录:mac的浏览器访问任何域名、网址都跳转到本地127.0.0.1或固定网址
新年上班第一天,刚开机就遇到了个小坑,问题是这样,打开浏览器,输入任何网址都跳转到本地的一个项目,该项目在本地Apache配置下,监听的端口是8888,本机访问的形式是127.0.0.1:8888. ...
- Quartz.NET 3.0 正式发布
Quartz.NET是一个强大.开源.轻量的作业调度框架,你能够用它来为执行一个作业而创建简单的或复杂的作业调度.它有很多特征,如:数据库支持,集群,插件,支持cron-like表达式等等.在2017 ...
- zabbix邮件报警设置
第一.安装邮件发送工具mailx 这里我选择的是mailx,所以的关闭其他的邮件发送工具 service sendmailstop #关闭 chkconfig sendmailoff #禁止开机启 ...
- Java并发系列[6]----Semaphore源码分析
Semaphore(信号量)是JUC包中比较常用到的一个类,它是AQS共享模式的一个应用,可以允许多个线程同时对共享资源进行操作,并且可以有效的控制并发数,利用它可以很好的实现流量控制.Semapho ...
- 网卡name-eth1如何修改为eth0
正常来说,Linux在识别网卡时第一张会是eth0,第二张才是eth1. 有时候我们使用虚拟机克隆技术后网卡的信息就会改变,新克隆出来的虚拟主机网卡名字可能变为eth1.无论我们怎么修改都无法改变,这 ...
- 传统IO与NIO(channel-to-channel)文件拷贝的探索与性能比对
Channel-to-channel传输是可以极其快速的,特别是在底层操作系统提供本地支持的时候.某些操作系统可以不必通过用户空间传递数据而进行直接的数据传输.对于大量的数据传输,这会是一个巨大的帮助 ...
- java线程优先级
java的线程优先级分为1-10 这10个等级 1为最强,最优先 10为最弱 如果大于10或者小于1则会抛异常 源代码为: public final void setPriority(int newP ...
- dubbox系列【四】——使用dubbo-monitor-x监控注册中心
1.下载源码,编译成war包 源码下载地址为:https://git.oschina.net/yjmyzz/dubbo-monitor.git 在pom.xml文件所在目录,直接执行mvn packa ...