https://blog.csdn.net/younghaiqing/article/details/81455410

C#多线程编程笔记(4.3)-Task任务中实现取消选项

https://blog.csdn.net/qq_35445058/article/details/80829339

1.Task类介绍:

Task 类的表示单个操作不返回一个值,通常以异步方式执行。 Task 对象是一个的中心思想 基于任务的异步模式 首次引入.NET Framework 4 中。 因为由执行工作 Task 对象通常以异步方式执行在线程池线程上而不是以同步方式在主应用程序线程,您可以使用 Status 属性,以及 IsCanceled, ,IsCompleted, ,和 IsFaulted 属性,以确定任务的状态。 大多数情况下,lambda 表达式用于指定的任务是执行的工作。

对于返回值的操作,您使用 Task 类。

任务Task和线程Thread的区别:

1、任务是架构在线程之上的,也就是说任务最终还是要抛给线程去执行。

2、任务跟线程不是一对一的关系,比如开10个任务并不是说会开10个线程,这一点任务有点类似线程池,但是任务相比线程池有很小的开销和精确的控制。

Task和Thread一样,位于System.Threading命名空间下!

一、创建Task

Task 类还提供了构造函数对任务进行初始化,但的未计划的执行。 出于性能原因, Task.Run 或 TaskFactory.StartNew(工厂创建) 方法是用于创建和计划计算的任务的首选的机制,但对于创建和计划必须分开的方案,您可以使用的构造函数(new一个出来),然后调用 Task.Start 方法来计划任务,以在稍后某个时间执行。

 //第一种创建方式,直接实例化:必须手动去Start
var task1 = new Task(() =>
{
//TODO you code
});
task1.Start(); //第二种创建方式,工厂创建,直接执行
var task2 = Task.Factory.StartNew(() =>
{
//TODO you code
});

二、Task的简略生命周期:

方法名 说明
Created 表示默认初始化任务,但是“工厂创建的”实例直接跳过。
WaitingToRun 这种状态表示等待任务调度器分配线程给任务执行。
RanToCompletion 任务执行完毕。
//查看Task中的状态
var task1 = new Task(() =>
{
Console.WriteLine("Begin");
System.Threading.Thread.Sleep(2000);
Console.WriteLine("Finish");
});
Console.WriteLine("Before start:" + task1.Status);
task1.Start();
Console.WriteLine("After start:" + task1.Status);
task1.Wait();
Console.WriteLine("After Finish:" + task1.Status); Console.Read();

三、Task的任务控制:Task最吸引人的地方就是他的任务控制了,你可以很好的控制task的执行顺序,让多个task有序的工作

方法名 说明
Task.Wait task1.Wait();就是等待任务执行(task1)完成,task1的状态变为Completed。
Task.WaitAll 待所有的任务都执行完成:
Task.WaitAny 发同Task.WaitAll,就是等待任何一个任务完成就继续向下执行
Task.ContinueWith 第一个Task完成后自动启动下一个Task,实现Task的延续
CancellationTokenSource 通过cancellation的tokens来取消一个Task。

下面详细介绍一下上面的几个方法:

1、Task.Wait

task1.Wait();就是等待任务执行(task1)完成,task1的状态变为Completed。

2、Task.WaitAll

看字面意思就知道,就是等待所有的任务都执行完成:

{
Task.WaitAll(task,task2,task3...N)
Console.WriteLine("All task finished!");
}

即当task,task2,task3…N全部任务都执行完成之后才会往下执行代码(打印出:“All task finished!”)

3、Task.WaitAny

这个用发同Task.WaitAll,就是等待任何一个任务完成就继续向下执行,将上面的代码WaitAll替换为WaitAny

{
Task.WaitAny(task,task2,task3...N)
Console.WriteLine("Any task finished!");
}

即当task,task2,task3…N任意一个任务都执行完成之后就会往下执行代码(打印出:” Any task finished!”)

4、Task.ContinueWith

就是在第一个Task完成后自动启动下一个Task,实现Task的延续,下面我们来看下他的用法,编写如下代码:

  static void Main(string[] args)
{
var task1 = new Task(() =>
{
Console.WriteLine("Task 1 Begin");
System.Threading.Thread.Sleep(2000);
Console.WriteLine("Task 1 Finish");
});
var task2 = new Task(() =>
{
Console.WriteLine("Task 2 Begin");
System.Threading.Thread.Sleep(3000);
Console.WriteLine("Task 2 Finish");
});
task1.Start();
task2.Start();
var result = task1.ContinueWith<string>(task =>
{
Console.WriteLine("task1 finished!");
return "This is task result!";
});
Console.WriteLine(result.Result.ToString());
Console.Read();
}

可以看到,task1完成之后,开始执行后面的内容,并且这里我们取得task的返回值。

5、Task的取消

前面说了那么多Task的用法,下面来说下Task的取消,比如我们启动了一个task,出现异常或者用户点击取消等等,我们可以取消这个任务。如何取消一个Task呢,我们通过cancellation的tokens来取消一个Task。在很多Task的Body里面包含循环,我们可以在轮询的时候判断IsCancellationRequested属性是否为True,如果是True的话就return或者抛出异常,抛出异常后面再说,因为还没有说异常处理的东西。

下面在代码中看下如何实现任务的取消,代码如下:

    var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var task = Task.Factory.StartNew(() =>
{
for (var i = 0; i < 1000; i++)
{
System.Threading.Thread.Sleep(1000);
if (token.IsCancellationRequested)
{
Console.WriteLine("Abort mission success!");
return;
}
}
}, token);
token.Register(() =>
{
Console.WriteLine("Canceled");
});
Console.WriteLine("Press enter to cancel task...");
Console.ReadKey();
tokenSource.Cancel();

这里开启了一个Task,并给token注册了一个方法,输出一条信息,然后执行ReadKey开始等待用户输入,用户点击回车后,执行tokenSource.Cancel方法,取消任务。

注:

  1. 因为任务通常运行以异步方式在线程池线程上,创建并启动任务的线程将继续执行,一旦该任务已实例化。 在某些情况下,当调用线程的主应用程序线程,该应用程序可能会终止之前任何任务实际开始执行。 其他情况下,应用程序的逻辑可能需要调用线程继续执行,仅当一个或多个任务执行完毕。 您可以同步调用线程的执行,以及异步任务它启动通过调用 Wait 方法来等待要完成的一个或多个任务。 若要等待完成一项任务,可以调用其 Task.Wait 方法。 调用 Wait 方法将一直阻塞调用线程直到单一类实例都已完成执行。

参考文献: 
1.https://www.cnblogs.com/yunfeifei/p/4106318.html 
2.https://msdn.microsoft.com/zh-cn/library/system.threading.tasks.task.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1

using System;
using System.Threading.Tasks;
using System.Threading; namespace 实现取消选项
{
class Program
{
static void Main(string[] args)
{
var cts = new CancellationTokenSource();
var longTask = new Task<int>(() => TaskMethod("Task 1", 10, cts.Token), cts.Token);
Console.WriteLine(longTask.Status);
cts.Cancel();
Console.WriteLine(longTask.Status);
Console.WriteLine("First task has been cancelled before execution"); cts = new CancellationTokenSource();
longTask = new Task<int>(() => TaskMethod("Task 2", 10, cts.Token), cts.Token);
longTask.Start();
for (int i = 0; i < 5; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine(longTask.Status);
}
cts.Cancel();
for (int i = 0; i < 5; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine(longTask.Status);
}
Console.WriteLine("A task has been completed with result {0}.", longTask.Result);
Console.ReadKey();
}
private static int TaskMethod(string name,int seconds,CancellationToken token)
{
Console.WriteLine("Task {0} is running on a thread id {1},Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsThreadPoolThread);
for (int i = 0; i < seconds; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(1));
if (token.IsCancellationRequested)
{
Console.WriteLine("Cancel Task {0} is running on a thread id {1},Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsThreadPoolThread);
return -1;
}
}
return 42 * seconds;
}
}
}

  

C# Task任务详解及其使用方式的更多相关文章

  1. JavaScript---Dom树详解,节点查找方式(直接(id,class,tag),间接(父子,兄弟)),节点操作(增删改查,赋值节点,替换节点,),节点属性操作(增删改查),节点文本的操作(增删改查),事件

    JavaScript---Dom树详解,节点查找方式(直接(id,class,tag),间接(父子,兄弟)),节点操作(增删改查,赋值节点,替换节点,),节点属性操作(增删改查),节点文本的操作(增删 ...

  2. Spring task任务调度详解

    spring内部有一个task是Spring自带的一个设定时间自动任务调度 task使用的时候很方便,但是他能做的东西不如quartz那么的多! 可以使用注解和配置两种方式,配置的方式如下 引入Spr ...

  3. Spring之AOP原理、代码、使用详解(XML配置方式)

    Spring 的两大核心,一是IOC,另一个是AOP,本博客从原理.AOP代码以及AOP使用三个方向来讲AOP.先给出一张AOP相关的结构图,可以放大查看. 一.Spring AOP 接口设计 1.P ...

  4. Activity的task相关 详解

    task是一个具有栈结构的容器,可以放置多个Activity实例.启动一个应用,系统就会为之创建一个task,来放置根Activity:默认情况下,一个Activity启动另一个Activity时,两 ...

  5. js if for 详解 获取元素方式 及一些js 基础知识

    ##获取元素的新方法## --document.querySelector('Css Selector{css选择器}') 接收一个css选择器(通配,群组,类,包含,id....等) 若这个选择器对 ...

  6. Spring AOP详解和实现方式

    一.什么是AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善. ...

  7. Spring系列(四):Spring AOP详解和实现方式(xml配置和注解配置)

    参考文章:http://www.cnblogs.com/hongwz/p/5764917.html 一.什么是AOP AOP(Aspect Oriented Programming),即面向切面编程, ...

  8. 利用EPX Studio将C/S程序转成B/S的方法详解(在线模块方式)

    采用 EPX 的在线模块,是最简单的方法,包括实现简单,客户端不需任何设置,客户使用就简单. 1. 设置服务器端参数(EPServer) 1.1 在服务配置工具选项卡中,设置服务项中的名称,路径,激活 ...

  9. Kubernetes ConfigMap详解,多种方式创建、多种方式使用

    我最新最全的文章都在南瓜慢说 www.pkslow.com,欢迎大家来喝茶! 1 简介 配置是程序绕不开的话题,在Kubernetes中使用ConfigMap来配置,它本质其实就是键值对.本文讲解如何 ...

随机推荐

  1. openfire存储中文字符乱码解决办法

    转载于: Xmpp问题总结:处理Openfire 中文乱码问题(2) openfire是一个非常不错的IM服务器,而且是纯Java实现,具有多个平台的版本,他的数据存储可以采用多种数据库,如MySQL ...

  2. POJ 1503 Integer Inquiry(大数相加)

    一.Description One of the first users of BIT's new supercomputer was Chip Diller. He extended his exp ...

  3. Poj 1017 Packets(贪心策略)

    一.题目大意: 一个工厂生产的产品用正方形的包裹打包,包裹有相同的高度h和1*1, 2*2, 3*3, 4*4, 5*5, 6*6的尺寸.这些产品经常以产品同样的高度h和6*6的尺寸包袱包装起来运送给 ...

  4. loadrunner的四个主要部件

    1.VUser Generator :性能脚本开发 2.Controller :提供多线程并发操作 3.Analysis :结果分析 4.Load Generator :负载生成器 ***负载生成器完 ...

  5. node包管理工具nvm

    去NVM官网下载NVM压缩包,下载nvm-setup.zip,直接傻瓜式安装 安装成功后运行命令: nvm -v 常用命令: nvm install <version> ## 安装指定版本 ...

  6. <正则吃饺子>:关于java中垃圾回收技术的简单学习总结

    知识介绍来自网络,后面会根据继续学习进行补充和适当的修改,谢谢!原文地址:http://www.importnew.com/26821.html#comment-578355 java中的垃圾回收机制 ...

  7. 利用java mail发送邮件

    import java.util.Date; import java.util.Properties; import javax.activation.DataHandler; import java ...

  8. python 学习笔记12(事件驱动、IO多路复用、异步IO)

    阻塞IO和非阻塞IO.同步IO和异步IO的区别 讨论背景:Linux环境下的network IO. 1.先决条件(几个重要概念) 1.1.用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32 ...

  9. [CentOS7] 设置开机启动方式(图形界面或命令行)

    由于CenOS之前一直都是通过修改inittab文件来修改开机启动模式,于是 通过 vim /etc/inittab 打开inittab来查看 如上所示,CentOS 7由于使用systemd而不是i ...

  10. LOJ6235 区间素数个数(min_25筛)

    题目链接:LOJ 题目大意:看到题目名字应该都知道是啥了吧. $1\le N\le 10^{11}$. 阉割版 min_25 筛.发现答案实际上就是 min_25 筛中 $g(N,pl)$ 的值.(取 ...