原文 8天玩转并行开发——第二天 Task的使用

在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于

“任务的编程模型”所冲击,因为task会比thread具有更小的性能开销,不过大家肯定会有疑惑,任务和线程到底有什么区别?

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

2:任务跟线程不是一对一的关系,比如开10个任务并不是说会开10个线程,这一点任务有点类似线程池,但是任务相比线程池有很小

的开销和精确的控制。

一:Task

1. 最简单的使用

开启task有两种方式:

<1> 实例化Task

1    //第一种方式开启
2 var task1 = new Task(() =>
3 {
4 Run1();
5 });

<2>从工厂中创建

1   var task2 = Task.Factory.StartNew(() =>
2 {
3 Run2();
4 });

是的,同样两种方法都可以创建,我们肯定会想两者是不是多多少少有点区别呢?好的,下面我们举个例子看分晓。

 1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;
4 using System.Diagnostics;
5 using System.Collections.Generic;
6
7 class Program
8 {
9 static void Main(string[] args)
10 {
11 //第一种方式开启
12 var task1 = new Task(() =>
13 {
14 Run1();
15 });
16
17 //第二种方式开启
18 var task2 = Task.Factory.StartNew(() =>
19 {
20 Run2();
21 });
22
23 Console.WriteLine("调用start之前****************************\n");
24
25 //调用start之前的“任务状态”
26 Console.WriteLine("task1的状态:{0}", task1.Status);
27
28 Console.WriteLine("task2的状态:{0}", task2.Status);
29
30 task1.Start();
31
32 Console.WriteLine("\n调用start之后****************************");
33
34 //调用start之前的“任务状态”
35 Console.WriteLine("\ntask1的状态:{0}", task1.Status);
36
37 Console.WriteLine("task2的状态:{0}", task2.Status);
38
39 //主线程等待任务执行完
40 Task.WaitAll(task1, task2);
41
42 Console.WriteLine("\n任务执行完后的状态****************************");
43
44 //调用start之前的“任务状态”
45 Console.WriteLine("\ntask1的状态:{0}", task1.Status);
46
47 Console.WriteLine("task2的状态:{0}", task2.Status);
48
49 Console.Read();
50 }
51
52 static void Run1()
53 {
54 Thread.Sleep(1000);
55 Console.WriteLine("\n我是任务1");
56 }
57
58 static void Run2()
59 {
60 Thread.Sleep(2000);
61 Console.WriteLine("我是任务2");
62 }
63 }

①:从图中可以看出两种task实例的简略生命周期。

Created:表示默认初始化任务,但是我们发现“工厂创建的”实例直接跳过。

WaitingToRun: 这种状态表示等待任务调度器分配线程给任务执行。

RanToCompletion:任务执行完毕。

②:我们发现task的使用跟Thread很相似,就连waitAll的方法使用也一样,刚才也说了,任务是架构在线程之上,那么我们用VS里面的

“并行任务”看一看,快捷键Ctrl+D,K,或者找到“调试"->"窗口“->"并行任务“,我们在WaitAll方法处插入一个断点,最终我们发现

任务确实托管给了线程。

2. 取消任务

我们知道task是并行计算的,比如说主线程在某个时刻由于某种原因要取消某个task的执行,我们能做到吗? 当然我们可以做到。

在4.0中给我们提供一个“取消标记”叫做CancellationTokenSource.Token,在创建task的时候传入此参数,就可以将主线程和任务相

关联,然后在任务中设置“取消信号“叫做ThrowIfCancellationRequested来等待主线程使用Cancel来通知,一旦cancel被调用。task将会

抛出OperationCanceledException来中断此任务的执行,最后将当前task的Status的IsCanceled属性设为true。看起来是不是很抽象,

没关系,上代码说话。

 1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;
4 using System.Diagnostics;
5 class Program
6 {
7 static void Main(string[] args)
8 {
9 var cts = new CancellationTokenSource();
10 var ct = cts.Token;
11
12 Task task1 = new Task(() => { Run1(ct); }, ct);
13
14 Task task2 = new Task(Run2);
15
16 try
17 {
18 task1.Start();
19 task2.Start();
20
21 Thread.Sleep(1000);
22
23 cts.Cancel();
24
25 Task.WaitAll(task1, task2);
26 }
27 catch (AggregateException ex)
28 {
29 foreach (var e in ex.InnerExceptions)
30 {
31 Console.WriteLine("\nhi,我是OperationCanceledException:{0}\n", e.Message);
32 }
33
34 //task1是否取消
35 Console.WriteLine("task1是不是被取消了? {0}", task1.IsCanceled);
36 Console.WriteLine("task2是不是被取消了? {0}", task2.IsCanceled);
37 }
38
39 Console.Read();
40 }
41
42 static void Run1(CancellationToken ct)
43 {
44 ct.ThrowIfCancellationRequested();
45
46 Console.WriteLine("我是任务1");
47
48 Thread.Sleep(2000);
49
50 ct.ThrowIfCancellationRequested();
51
52 Console.WriteLine("我是任务1的第二部分信息");
53 }
54
55 static void Run2()
56 {
57 Console.WriteLine("我是任务2");
58 }
59 }

从图中可以看出

①:Run1中的Console.WriteLine("我是任务1的第二部分信息"); 没有被执行。

②:Console.WriteLine("task1是不是被取消了? {0}", task1.IsCanceled); 状态为True。

也就告诉我们Run1中途被主线程中断执行,我们coding的代码起到效果了。

3. 获取任务的返回值

我们以前写线程的时候注册的方法一般都是void类型,如果主线程要从工作线程中获取数据一般采用的手段是“委托+事件”的模式,然而

在Task中有两种方式可以解决。

<1>  现在我们的实例化是采用Task<TResult>的形式,其中TResult就是当前task执行后返回的结果,下面举得例子是t2任务获取

t1的执行结果。

 1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;
4 using System.Diagnostics;
5 using System.Collections.Generic;
6
7 class Program
8 {
9 static void Main(string[] args)
10 {
11 //执行task1
12 var t1 = Task.Factory.StartNew<List<string>>(() => { return Run1(); });
13
14 t1.Wait();
15
16 var t2 = Task.Factory.StartNew(() =>
17 {
18 Console.WriteLine("t1集合中返回的个数:" + string.Join(",", t1.Result));
19 });
20
21 Console.Read();
22 }
23
24 static List<string> Run1()
25 {
26 return new List<string> { "1", "4", "8" };
27 }
28 }

<2>采用ContinueWith方法,很有意思,现在我们将上面的方法改造一下。

 1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;
4 using System.Diagnostics;
5 using System.Collections.Generic;
6
7 class Program
8 {
9 static void Main(string[] args)
10 {
11 //执行task1
12 var t1 = Task.Factory.StartNew<List<string>>(() => { return Run1(); });
13
14 var t2 = t1.ContinueWith((i) =>
15 {
16 Console.WriteLine("t1集合中返回的个数:" + string.Join(",", i.Result));
17 });
18
19 Console.Read();
20 }
21
22 static List<string> Run1()
23 {
24 return new List<string> { "1", "4", "8" };
25 }
26 }

4:ContinueWith结合WaitAll来玩一把

当这两者结合起来,我们就可以玩一些复杂一点的东西,比如说现在有7个任务,其中t1需要串行,t2-t3可以并行,t4需要串行,t5-t6并行,

t7串行。

好了,我们上一下代码说话,下面代码没有实际意思,纯属演示。

 1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;
4 using System.Diagnostics;
5 using System.Collections.Generic;
6 using System.Collections.Concurrent;
7
8 class Program
9 {
10 static void Main(string[] args)
11 {
12 ConcurrentStack<int> stack = new ConcurrentStack<int>();
13
14 //t1先串行
15 var t1 = Task.Factory.StartNew(() =>
16 {
17 stack.Push(1);
18 stack.Push(2);
19 });
20
21 //t2,t3并行执行
22 var t2 = t1.ContinueWith(t =>
23 {
24 int result;
25
26 stack.TryPop(out result);
27 });
28
29 //t2,t3并行执行
30 var t3 = t1.ContinueWith(t =>
31 {
32 int result;
33
34 stack.TryPop(out result);
35 });
36
37 //等待t2和t3执行完
38 Task.WaitAll(t2, t3);
39
40
41 //t4串行执行
42 var t4 = Task.Factory.StartNew(() =>
43 {
44 stack.Push(1);
45 stack.Push(2);
46 });
47
48 //t5,t6并行执行
49 var t5 = t4.ContinueWith(t =>
50 {
51 int result;
52
53 stack.TryPop(out result);
54 });
55
56 //t5,t6并行执行
57 var t6 = t4.ContinueWith(t =>
58 {
59 int result;
60
61 //只弹出,不移除
62 stack.TryPeek(out result);
63 });
64
65 //临界区:等待t5,t6执行完
66 Task.WaitAll(t5, t6);
67
68 //t7串行执行
69 var t7 = Task.Factory.StartNew(() =>
70 {
71 Console.WriteLine("当前集合元素个数:" + stack.Count);
72 });
73
74 Console.Read();
75 }
76 }

8天玩转并行开发——第二天 Task的使用的更多相关文章

  1. [转]8天玩转并行开发——第二天 Task的使用

    在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于 “任务的编程模型”所冲击,因为task会比thread具有更小的性能开销,不 ...

  2. 8天玩转并行开发——第三天 plinq的使用

    原文 8天玩转并行开发——第三天 plinq的使用 相信在.net平台下,我们都玩过linq,是的,linq让我们的程序简洁优美,简直玩的是爱不释手,但是传统的linq只是串行代码,在并行的 年代如果 ...

  3. 8天玩转并行开发——第八天 用VS性能向导解剖你的程序

    原文 8天玩转并行开发——第八天 用VS性能向导解剖你的程序 最后一篇,我们来说说vs的“性能向导",通常我们调试程序的性能一般会使用Stopwatch,如果希望更加系统的了解程序,我们就需 ...

  4. 8天玩转并行开发——第一天 Parallel的使用

    转自:http://www.cnblogs.com/huangxincheng/archive/2012/04/02/2429543.html 随着多核时代的到来,并行开发越来越展示出它的强大威力,像 ...

  5. C#并行开发_Thread/ThreadPool, Task/TaskFactory, Parallel

    大家好,本次讨论的是C#中的并行开发,给力吧,随着并行的概念深入,哥也赶上这个潮流了,其实之前讨论C#的异步调用或者C#中BeginInvoke或者Invoke都已经涉及了部分本篇的内容. 参考书目: ...

  6. 并行开发 2.plink

    原文:8天玩转并行开发——第二天 Task的使用 在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于 “任务的编程模型”所冲击, ...

  7. 并行开发 2.task

    原文:8天玩转并行开发——第二天 Task的使用 在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于 “任务的编程模型”所冲击, ...

  8. 并行开发 1.Parallel

    原文:8天玩转并行开发——第一天 Parallel的使用 随着多核时代的到来,并行开发越来越展示出它的强大威力,像我们这样的码农再也不用过多的关注底层线程的实现和手工控制, 要了解并行开发,需要先了解 ...

  9. 并行开发学习随笔1——plinq并行

    这两天在看园友的文章 <8天玩转并行开发——第三天 plinq的使用> 对里面的第一个实例亲手实践了一下,发现了一点有意思的事情. 测试环境:.net 4.5 64位(如果是32位的,测试 ...

随机推荐

  1. HH的军训(容斥)

    1248: HH的军训 时间限制: 1 Sec  内存限制: 128 MB 提交: 95  解决: 11 [提交][状态][讨论版] 题目描述 大学里,最难忘的事情莫过于军训了,白白的HH童鞋就被无情 ...

  2. JS - 删除确认

    <a href="javascript:if(confirm('确实要删除吗?'))location='<{:U('Admin/Update/deleteuserinfo', a ...

  3. AS3清空数组的四种方法

    第一种最简单的方法是: var arr:Array = ["a", "b", "c", "d", "e&quo ...

  4. python读写xml

    来自http://blog.csdn.net/liuyuehui110/article/details/7287897 备份防止链接失效 一.XML的读取. 在 NewEdit 中有代码片段的功能,代 ...

  5. HDU 5025Saving Tang Monk BFS + 二进制枚举状态

    3A的题目,第一次TLE,是因为一次BFS起点到终点状态太多爆掉了时间. 第二次WA,是因为没有枚举蛇的状态. 解体思路: 因为蛇的数目是小于5只的,那就首先枚举是否杀死每只蛇即可. 然后多次BFS, ...

  6. CSS 规避脱标之两种用法

    大家好,我是小强老师,今天讲解一小点知识哈 对比了才知道什么好 看不出,很漂亮吧! 有木有倾国倾城的美色. 呵呵,好多东西也是这样的,好的东西只有对比了才觉得好. 我们知道我们网页布局 有三模式.   ...

  7. Python 2.7 学习笔记 面向对象的编程

    python是一种面向对象的语言.本文介绍如何用python进行面向对象的编程. 首先我们说下对象和类,类是一种类型的定义,对象是类的实例. 一.内置对象类型(内置类) 其实我们前面已经大量用到了对象 ...

  8. IBM Python 技术专题

    Python 技术专题 Python 是由 Guido van Rossum 开发的,可免费获得的.是一种非常高级的解释型语言.其语法简单易懂,而且面向对象的语义功能强大又灵活,Python 可以广泛 ...

  9. libevent: linux安装libevent

    http://libevent.org/上下载最新的libevent, 如 libevent-2.0.22-stable.tar.gz. 然后解压,按照README里面的步骤安装.

  10. 最新Cocos2d-x3.2开发环境搭建(windows环境下)

    原文地址:http://cache.baiducontent.com/c?m=9d78d513d9921cfe05ac837f7d16c067690297634d9dc7150ed58449e3735 ...