.net task
Task 是4.0里面带来的一个很好用的线程类,后台也是由线程池控制的
有时间是里面的方法得好好看看。
今天学到一个新的。
当需要两个操作并行执行,然后再线性执行时。可以先
Task1
Task2执行
Task.Factory.ContinueWhenAll(new Task[]{task1,task2},new Action<Task[]>((p)=>{}))
如果这是在单个线程里面:
task2里面的操作必须等待task1执行完以后才能执行。通过上面的方法就可以并行执行了 wool,nice job
http://www.cnblogs.com/yuzhaolangzi/archive/2010/11/29/1891333.html
随着 .NET 4.0的到来,她与以前各版本的一个明显差别就是并行功能的增强,以此来适应这个多核的世界。于是引入了一个新概念---任务,作为支持并行运算的重要组成部分,同时,也作为对线程池的一个补充和完善。从所周知,使用线程池有两个明显的缺点,那就是一旦把我们要执行的任务放进去后,什么时候执行完成,以及执行完成后需要返回值,我们都无法通过内置的方式而得知。由于任务(Task)的推出,使得我们对并行编程变得简单,而且不用关心底层是怎么实现的,由于比线程池更灵活,如果能掌握好Task,对于写出高效的并行代码非常有帮助。
一、新建任务
在System.Threading.Tasks命名空间下,有两个新类,Task及其泛型版本Task<TResult>,这两个类是用来创建任务的,如果执行的代码不需要返回值,请使用Task,若需要返回值,请使用Task<TResult>。
创建任务的方式有两种,一种是通过Task.Factory.StartNew方法来创建一个新任务,如:
Task task = Task.Facotry.StartNew(()=>Console.WriteLine(“Hello, World!”));//此行代码执行后,任务就开始执行
另一种方法是通过Task类的构造函数来创建一个新任务,如:
Task task = new Task(()=>Console.WriteLine(“Hello, World!”));//此处只把要完成的工作交给任务,但任务并未开始
task.Start();//调用Start方法后,任务才会在将来某个时候开始执行。
同时,我们可以调用Wait方法来等待任务的完成或者调用IsCompleted属性来判断任务是否完成。需要说明的是,两种创建任务的方法都可以配合TaskCreationOptions枚举来实现我们对任务执行的行为具体控制, 同时,这两种创建方式允许我们传递一个TaskCreationOptions对象来取消正在运行中的任务,请看任务的取消。
二、任务的取消
这世界唯一不变的就是变化,当外部条件发生变化时,我们可能会取消正在执行的任务。对于.NET 4.0之前,.NET并未提供一个内置的解决方案来取消线程池中正在执行的代码,但在.NET 4.0中,我们有了Cooperative Cancellation模式,这使得取消正在执行的任务变得非常简单。如下所示:
using System;
using System.Threading;
using System.Threading.Tasks;namespace TaskDemo
{
class Program
{
static void Main()
{
CancellationTokenSource cts = new CancellationTokenSource();
Task t = new Task(() => LongRunTask(cts.Token));
t.Start();
Thread.Sleep(2000);
cts.Cancel();
Console.Read();
}static void LongRunTask(CancellationToken token)
{//此处方法模拟一个耗时的工作
for (int i = 0; i < 1000; i++)
{
if (!token.IsCancellationRequested)
{
Thread.Sleep(500);
Console.Write(".");
}
else
{
Console.WriteLine("任务取消");
break;
}
}
}
}
}
三、任务的异常机制
在任务执行过程中产生的未处理异常,任务会把它暂时隐藏起来,装进一个集合中。当我们调用Wait方法或者Result属性时,任务会抛出一个AggregateException异常。我们可以通过调用AggregateException对象的只读属性InnerExceptions来得到一个ReadOnlyCollection<Exception>对象,它才是存储抛出异常的集合,它的第一个元素就是最初抛出的异常。同样的,AggregateException对象的InnerException属性也会返回最初抛出的异常。
值得重视的是,由于任务的隐藏机制的特点,一旦产生异常后,如果我们不调用相应的方法或者属性查看异常,我们也无法判断是否有异常产生(Task不会主动抛出异常)。当Task对象被GC回收时,Finalize方法会查检是否有未处理的异常,如果不幸刚才好有,则Finalize方法会将此AggregateException再度抛出,如果再不幸,我们没有捕获处理这个异常,则我们的程序会立即中止运行。如果发生这样的事情,会是多么大的灾难啊!
为了避免这种不幸的发生,我们可以通过注册TaskScheduler类的静态UnobservedTaskException事件来处理这种未被处理的异常,避免程序的崩溃。
四、任务启动任务
任务的强大与灵活之一是,当我们完成一个任务时,可以自动开始一个新任务的执行。如下所示:
using System;
using System.Threading;
using System.Threading.Tasks;namespace TaskDemo
{
public class AutoTask
{
static void Main()
{
Task task = new Task(() => { Thread.Sleep(5000); Console.WriteLine("Hello,"); Thread.Sleep(5000); });
task.Start();
Task newTask = task.ContinueWith(t => Console.WriteLine("World!"));
Console.Read();
}
}
}对于ContinueWith方法,我们可以配合TaskContinuationOptions枚举,得到更多我们想要的行为。
五、子任务
任务是支持父子关系的,即在一个任务中创建新任务。如下所示:
using System;
using System.Threading.Tasks;namespace TaskDemo
{
class ChildTask
{
static void Main()
{
Task parant = new Task(() =>
{
new Task(() => Console.WriteLine("Hello")).Start();
new Task(() => Console.WriteLine(",")).Start();
new Task(() => Console.WriteLine("World")).Start();
new Task(() => Console.WriteLine("!")).Start();
});
parant.Start();
Console.ReadLine();
}
}
}值得注意的是,以上代码中所示的子任务的调用并不是以代码的出现先后为顺序来调用的。
六、任务工厂
在某些情况下,我们会遇到创建大量的任务,而恰好这些任务共用某个状态参数(如CancellationToken),为了避免大量的调用任务的构造器和一次又一次的参数传递,我们可以使用任务工厂来为我们处理这种大量创建工作。如下代码所示:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace TaskDemo
{
public class FactoryOfTask
{
static void Main()
{
Task parent = new Task(() =>
{
CancellationTokenSource cts = new CancellationTokenSource();
TaskFactory tf = new TaskFactory(cts.Token);
var childTask = new[]
{
tf.StartNew(()=>ConcreteTask(cts.Token)),
tf.StartNew(()=>ConcreteTask(cts.Token)),
tf.StartNew(()=>ConcreteTask(cts.Token))
};
Thread.Sleep(5000);//此处睡眠等任务开始一定时间后才取消任务
cts.Cancel();
}
);
parent.Start();//开始执行任务
Console.Read();
}
static void ConcreteTask(CancellationToken token)
{
while (true)
{
if (!token.IsCancellationRequested)
{
Thread.Sleep(500);
Console.Write(".");
}
else
{
Console.WriteLine("任务取消");
break;
}
}
}
}
}
七、任务调度程序
任务的调度通过调度程序来实现的,目前,.NET 4.0内置两种任务调度程序:线程池任务调度程序(thread pool task scheduler)和同步上下文任务调度程序(synchronization context task scheduler)。默认情况下,应用程序使用线程池任务调度程序调用线程池的工作线程来完成任务,如受计算限制的异步操作。同步上下文任务调度程序通常使用UI线程来完成与Windows Forms,Windows Presentation Foundation(WPF)以及SilverLight应用程序相关的任务。
可喜的是,.NET 4.0 提供了TaskScheduler抽象类供开发人员继承来实现自定义任务调度程序的开发,有兴趣的同学可以试试。
八、总结
任务给了我们更多的方便性、灵活性的同时,也带来了比线程池更多的资源消耗。如果想减少资源消耗,请直接使用线程池QueueUserWorkItem方法效果会更好;如果想要更多的控制与灵活性,任务(Task)是不二的选择。这个要我们开发者自己去斟酌了。
参考文献:《CLR Via C#》,Third edtion, 作者:Jeffrey Richer,726页-739页
《Introducing .NET 4.0 With Visual Studio 2010》,作者:Alex Mackey,106页-111页
.net task的更多相关文章
- Concepts:Request 和 Task
当SQL Server Engine 接收到Session发出的Request时,SQL Server OS将Request和Task绑定,并为Task分配一个Workder.在TSQL Query执 ...
- .Net多线程编程—任务Task
1 System.Threading.Tasks.Task简介 一个Task表示一个异步操作,Task的创建和执行是独立的. 只读属性: 返回值 名称 说明 object AsyncState 表示在 ...
- nginx+iis+redis+Task.MainForm构建分布式架构 之 (redis存储分布式共享的session及共享session运作流程)
本次要分享的是利用windows+nginx+iis+redis+Task.MainForm组建分布式架构,上一篇分享文章制作是在windows上使用的nginx,一般正式发布的时候是在linux来配 ...
- windows+nginx+iis+redis+Task.MainForm构建分布式架构 之 (nginx+iis构建服务集群)
本次要分享的是利用windows+nginx+iis+redis+Task.MainForm组建分布式架构,由标题就能看出此内容不是一篇分享文章能说完的,所以我打算分几篇分享文章来讲解,一步一步实现分 ...
- Openstack Periodic Task
Openstack Periodic Task 周期性任务在各个模块的manager.py(computer,scheduler,cell,network)中添加. 添加方法:在模块manager类实 ...
- MapReduce剖析笔记之三:Job的Map/Reduce Task初始化
上一节分析了Job由JobClient提交到JobTracker的流程,利用RPC机制,JobTracker接收到Job ID和Job所在HDFS的目录,够早了JobInProgress对象,丢入队列 ...
- [Java定时器]用Spring Task实现一个简单的定时器.
今天做一个项目的的时候需要用到定时器功能.具体需求是: 每个月一号触发一次某个类中的方法去拉取别人的接口获取上一个月份车险过期的用户.如若转载请附上原文链接:http://www.cnblogs.co ...
- 定时管理器框架-Task.MainForm
入住博客园4年多了,一直都是看别人的博客,学习别人的知识,为各个默默无私贡献自己技术总结的朋友们顶一个:这几天突然觉得是时候加入该队列中,贡献出自己微弱的力量,努力做到每个月有不同学习总结,知识学习的 ...
- Task三个列子的分享
这次要分享的是C#Task任务的几个列子,感觉最实用的是封装的分页任务执行方法,这个方法步奏也是目前在我工作中执行多任务常用的,不知道各位也有这用的情况,那么开始吧. 1.顺序任务执行 //顺序任务执 ...
- webapi+Task并行请求不同接口实例
标题的名称定义不知道是否准确,不过我想表达的意思就是使用Task特性来同时请求多个不同的接口,然后合并数据:我想这种场景的开发对于对接过其他公司接口的人不会陌生,本人也是列属于之内,更多的是使用最原始 ...
随机推荐
- centos 命令行 连接无线网卡
ifconfig wlan0 up 1 ifconfig wlan0 iwlist wlan0 scan wpa_passphrase naizhongnai naizhong >> /e ...
- SDCycleScrollView 添加初始滚动页码
最近在做一个无限轮播界面,由于自己写的有些卡顿,所以我使用了第三方框架SDCycleScrollView,但是我的初始滚动页不是从第一页开始怎么办,我想从第二页,第三页,或者最后一页,关于这个SDCy ...
- oc知道经纬度求位置
CLLocation *newLocation = [locations lastObject]; CLGeocodeCompletionHandler handler = ^(NSArray *pl ...
- Linux中切换用户变成-bash4.1-$的解决方法【转】
转自 Linux中切换用户变成-bash4.1-$的解决方法 - xia_xia的博客 - 博客频道 - CSDN.NEThttp://blog.csdn.net/xia_xia0919/articl ...
- nuget pack 时不包含依赖包(而不是引用项目的dll,区别于IncludeReferencedProjects)
Excluding development dependencies when creating packages Some NuGet packages are useful as developm ...
- Mycat 依赖包解读
1.curator - zookeeper开源客户端框架 2.dom4j - xml解析包 3.druid - 阿里巴巴推出的国产数据库连接池,同时具备监控功能,性能优于JDBC和C3P0 4.ehc ...
- 国内的cdn
测试了一下,百度的非常快 ----------------------------------------------------------------------- 原文:https://www. ...
- ligerUI调用$.ligerDialog.open弹出窗口,关闭后无法获取焦点问题
1:调用父窗口某一个文件框,获取焦点, parent.window.document.getElementByIdx_x("roleName").focus(); 2:关闭父窗 ...
- Webkit之资源加载
一.webkit资源分类 webkit中有多种资源,大致分为以下几种: HTML文本 CSS样式文本 - CachedCSSStyleSheet 字体 - CachedFont 图片 - Cached ...
- FTP: Configuring server users..
4 points to create a user to uploade to ftproot.. this user must be an administrator, and be able to ...