.Net中Task Parallel Library的基本用法

我们知道,每个应用程序就是一个进程,一个进程有多个线程。Task Parallel Library为我们的异步编程、多线程编程提供了强有力的支持,它允许一个主线程运行的同时,另外的一些线程或Task也同时运行。本篇体验基本用法。

基本用法

Taks的构造函数接收的类型是Action,也就是一个委托。

        static void Main(string[] args)
        {
            var t1 = new Task(() =>
            {
                Console.WriteLine("任务1开始");
                Thread.Sleep(1000);
                Console.WriteLine("任务1结束");
            });
            t1.Start();
            Console.ReadKey();
        }

如果把方法放到外面。

        static void Main(string[] args)
        {
            var t1 = new Task(() => DoSth(1,2000));
            t1.Start();
            Console.ReadKey();
        }
        static void DoSth(int id, int sleepTime)
        {
            Console.WriteLine("任务{0}开始",id);
            Thread.Sleep(sleepTime);
            Console.WriteLine("任务{0}结束",id);
        }

如果有多个Task同时执行。

        static void Main(string[] args)
        {
            var t1 = new Task(() => DoSth(1,2000));
            t1.Start();
            var t2 = new Task(() => DoSth(2, 1500));
            t2.Start();
            var t3 = new Task(() => DoSth(3, 3000));
            t3.Start();
            Console.ReadKey();
        }

如果有很多Task,每个Task手动启动的话很费事,Task Parallel Library为我们准备了Task工厂。

        static void Main(string[] args)
        {
            var t1 = Task.Factory.StartNew(() => DoSth(1, 2000));
            var t2 = Task.Factory.StartNew(() => DoSth(2, 1500));
            var t3 = Task.Factory.StartNew(() => DoSth(3, 3000));
            Console.ReadKey();
        }

如果我们想在一个任务结束之后立即执行某个任务,可以使用ContinueWith方法。

        static void Main(string[] args)
        {
            var t1 = Task.Factory.StartNew(() => DoSth(1, 2000)).ContinueWith((pre)=> DoOtherThing(4,2000));
            var t2 = Task.Factory.StartNew(() => DoSth(2, 1500));
            var t3 = Task.Factory.StartNew(() => DoSth(3, 3000));
            Console.ReadKey();
        }
        static void DoSth(int id, int sleepTime)
        {
            Console.WriteLine("任务{0}开始",id);
            Thread.Sleep(sleepTime);
            Console.WriteLine("任务{0}结束",id);
        }
        static void DoOtherThing(int id, int sleepTime)
        {
            Console.WriteLine("其他任务{0}开始", id);
            Thread.Sleep(sleepTime);
            Console.WriteLine("其他任务{0}结束", id);
        }

如果希望等待所有的Task执行完毕,使用WaitAll方法。

        static void Main(string[] args)
        {
            var t1 = Task.Factory.StartNew(() => DoSth(1, 2000));
            var t2 = Task.Factory.StartNew(() => DoSth(2, 1500));
            var t3 = Task.Factory.StartNew(() => DoSth(3, 3000));
            var taskList = new List<Task> {t1, t2, t3};
            Task.WaitAll(taskList.ToArray());
            Console.WriteLine("我是在所有Task执行完毕后才执行的");
            Console.ReadKey();
        }

如果想手动取消结束某个Task,需要为方法带上CancellationToken类型参数。

        static void Main(string[] args)
        {
            var source = new CancellationTokenSource();
            try
            {
                var t1 =
                    Task.Factory.StartNew(() => DoSth(1, 1000, source.Token))
                        .ContinueWith((pre) => DoOtherThing(2, 2000));
                source.Cancel();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.GetType());
            }
            Console.WriteLine("haha");
            Console.ReadKey();
        }
        static void DoSth(int id, int sleepTime, CancellationToken token)
        {
            if (token.IsCancellationRequested)
            {
                Console.WriteLine("任务被取消");
                token.ThrowIfCancellationRequested();
            }

            Console.WriteLine("任务{0}开始",id);
            Thread.Sleep(sleepTime);
            Console.WriteLine("任务{0}结束",id);
        }
        static void DoOtherThing(int id, int sleepTime)
        {
            Console.WriteLine("其他任务{0}开始", id);
            Thread.Sleep(sleepTime);
            Console.WriteLine("其他任务{0}结束", id);
        }

如何从Task从获取方法的返回结果呢?

        static void Main(string[] args)
        {
            Console.WriteLine("开始计算");
            Task<int> t = Task.Factory.StartNew(() => Sum(1, 2));
            Console.WriteLine("等待结果");
            Console.WriteLine(t.Result);
            Console.ReadKey();
        }
        static int Sum(int a, int b)
        {
            return a + b;
        }

后面一个Task获取前面一个Task的返回值。

        static void Main(string[] args)
        {
            Task<string> firstTask = Task.Factory.StartNew<string>(() =>
            {
                Console.WriteLine("第一个任务开始");
                return "hi from the one";
            });
            Task secondTask = firstTask.ContinueWith((prevoursTask) =>
            {
                Console.WriteLine("这里是第二个任务,获取到第一个任务的返回值是{0}",prevoursTask.Result,TaskContinuationOptions.OnlyOnRanToCompletion);
            });
            secondTask.Wait();
            Console.ReadKey();
        }

等待所有Task完成。

        static void Main(string[] args)
        {
           var t1 =  Task.Factory.StartNew(() =>
            {
                Console.WriteLine("第一个任务");
                Thread.Sleep(1000);
            });
            var t2 = Task.Factory.StartNew(() =>
            {
                Console.WriteLine("第二个任务");
                Thread.Sleep(1000);
            });
            var taskList = new List<Task> {t1, t2};
            Task.Factory.ContinueWhenAll(taskList.ToArray(), (t) => { Console.WriteLine("所有任务完成我就出来"); });
            Console.ReadKey();
        }

如果是嵌套Task。

        static void Main(string[] args)
        {
            Task.Factory.StartNew(() =>
            {
                Task child = Task.Factory.StartNew(() =>
                {
                    Console.WriteLine("我是子任务");
                }, TaskCreationOptions.AttachedToParent);
            }).Wait();
            Console.ReadKey();
        }

启动Task的几种方式

1、通过Task.Factory.StartNew方法。

        static void Main(string[] args)
        {
            Task.Factory.StartNew(() => SaySth("hello"));
            Console.ReadKey();
        }
        static void SaySth(string msg)
        {
            Console.WriteLine(msg);
        }

2、通过Task的Start实例方法

        static void Main(string[] args)
        {
            var t = new Task(() => SaySth("hello"));
            t.Start();
            Console.ReadKey();
        }

或者干脆用委托。

        static void Main(string[] args)
        {
            Task t = new Task(delegate {SaySth("hello");});
            t.Start();
            Console.ReadKey();
        }

3、Task的静态方法Run

        static void Main(string[] args)
        {
            Task t = Task.Run(() => SaySth("hello"));
            Console.ReadKey();
        }
        static void SaySth(string msg)
        {
            Console.WriteLine(msg);
        }  

一个例子

比如说要下载某个页面,在保持当前UI界面无影响的情况下,使用Task在后台启动任务下载某个页面。

        static void Main(string[] args)
        {
            Console.WriteLine("界面内容");
            Task<string> r = DownloadAsync("http://www.baidu.com");
            while (!r.IsCompleted)
            {
                Console.Write(".");
                Thread.Sleep(250);
            }
            Console.WriteLine(r.Result);
            Console.ReadKey();
        }
        private static string DownloadWebPage(string url)
        {
            WebRequest request = WebRequest.Create(url);
            WebResponse response = request.GetResponse();
            var reader = new StreamReader(response.GetResponseStream());
            return reader.ReadToEnd();
        }
        private static Task<string> DownloadAsync(string url)
        {
            return Task.Factory.StartNew(() => DownloadWebPage(url));
        }

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接

(0)

相关推荐

  • C#中Parallel类For、ForEach和Invoke使用介绍

    一.简介: Parallel类提供了数据和任务的并行性:Paraller.For()方法类似于C#的for循环语句,也是多次执行一个任务.使用Paraller.For()方法,可以并行运行迭代,迭代的顺序没有定义.在For()方法中,前两个参数是固定的,这两个参数定义了循环的开头和结束.首先描述它的第一个方法For(int,int,Action<int>),前面两个参数代表循环的开头和介绍,第三个参数是个委托,整数参数是循环的迭代次数,该参数被传递给委托引用的方法.Paraller.For()

  • C#并行库Parallel类介绍

    Parallel.Invoke 这个函数的功能和Task有些相似,就是并发执行一系列任务,然后等待所有完成.和Task比起来,省略了Task.WaitAll这一步,自然也缺少了Task的相关管理功能.它有两种形式: Parallel.Invoke( params Action[] actions); Parallel.Invoke(Action[] actions,TaskManager manager,TaskCreationOptions options); 第二种方式可以自定义一个Task

  • C#任务并行Parellel.For和Parallel.ForEach

    简介:任务并行库(Task Parellel Library)是BCL的一个类库,极大的简化了并行编程. 使用任务并行库执行循环 C#当中我们一般使用for和foreach执行循环,有时候我们呢的循环结构每一次的迭代需要依赖以前一次的计算或者行为.但是有时候则不需要.如果迭代之间彼此独立,并且程序运行在多核处理器上,如果能将不同的迭代放到不同的处理器上并行处理,则会获益匪浅.Parallel.For和Parallel.ForEach就是为此而生的. ①使用Parallel.For 声明如下: 这

  • C#多线程之Parallel类的用法

    Parallel类是对线程的一个抽象.该类位于System.Threading.Tasks名称空间中,提供了数据和任务并行性. Paraller类定义了数据并行地For和ForEach的静态方法,以及任务并行的Invoke的静态方法.Parallel.For()和Parallel.ForEach()方法在每次迭代中调用相同的代码,Paraller.Invoke()允许调用不同的方法. 1.Parallel.For Parallel.For()方法类似C#语法的for循环语句,多次执行一个任务.但

  • C#并行编程之数据并行Tasks.Parallel类

    目录 一.并行概念 1.并行编程 2.数据并行 二.Parallel.Invoke():并行调用多个任务 . 三.Parallel.For(): for 循环的并行运算 四.Parallel.ForEach():foreach 循环的并行运算 五.线程局部变量 1.Parallel.For中定义局部变量: 2.Parallel.Each中定义局部变量: 六.Break.Stop中断与停止线程 七.Cancel取消循环 八.Handel Exceptions异常处理 一.并行概念 1.并行编程 在

  • C#多线程学习之Thread、ThreadPool、Task、Parallel四者区别

    目录 Thread ThreadPool Task Parallel Task专讲 线程(英语:thread)是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务.进程是资源分配的基本单位.所有与该进程有关的资源,都被记录在进程控制块PCB中.以表示该进程拥有这些资源或正在使用它们.本文以一些简单的小例子,简述多线程的发展历程[Thread,ThreadPool,Task

  • .Net中Task Parallel Library的基本用法

    我们知道,每个应用程序就是一个进程,一个进程有多个线程.Task Parallel Library为我们的异步编程.多线程编程提供了强有力的支持,它允许一个主线程运行的同时,另外的一些线程或Task也同时运行.本篇体验基本用法. 基本用法 Taks的构造函数接收的类型是Action,也就是一个委托. static void Main(string[] args) { var t1 = new Task(() => { Console.WriteLine("任务1开始"); Thr

  • python中Task封装协程的知识点总结

    说明 1.Task是Future的子类,Task是对协程的封装,我们把多个Task放在循环调度列表中,等待调度执行. 2.Task对象可以跟踪任务和状态.Future(Task是Futrue的子类)为我们提供了异步编程中最终结果的处理(Task类还具有状态处理功能). 3.把协程封装成Task,加入一个队列等待调用.刚创建Task的时候不执行,遇到await就执行. 实例 import asyncio async def func(): print(1) await asyncio.sleep(

  • AngularJS中$apply方法和$watch方法用法总结

    本文实例总结了AngularJS中$apply方法和$watch方法用法.分享给大家供大家参考,具体如下: 引言 最近在项目中封装控件的时候用到了$watch方法来监听module中的值的变化,当时小编对这个方法不是很了解,所以在网上找了一些资料来学习一下,下面小编就给大家简单介绍一些AngularJS中Scope 提供$apply 方法传播Model 的变化和$watch方法监听module变化. $apply使用情景 AngularJS 外部的控制器(DOM 事件.外部的回调函数如 jQue

  • 深入理解C++中public、protected及private用法

    初学C++的朋友经常在类中看到public,protected,private以及它们在继承中表示的一些访问范围,很容易搞糊涂.今天本文就来十分分析一下C++中public.protected及private用法.相信对于大家深入掌握C++程序设计会有很大的帮助. 这里我们首先要明白下面几点. 1.类的一个特征就是封装,public和private作用就是实现这一目的.所以: 用户代码(类外)可以访问public成员而不能访问private成员:private成员只能由类成员(类内)和友元访问.

  • javascript编程开发中取色器及封装$函数用法示例

    本文实例讲述了javascript编程开发中取色器及封装$函数用法.分享给大家供大家参考,具体如下: 1.封装$函数 function $(str){ //如果传入的是'#' 则选择id标签 //如果传入的是'.' 则选择所有的类名标签 //如果传入的既不是'#也不是'.' 选择复合标签 //判断传入的值 if(typeof str !='string'){ console.log('传入的参数有误!'); return null; } //获取参数的第一个字母 var firstChar=st

  • 深入浅析SQL中的group by 和 having 用法

    一.sql中的group by 用法解析: Group By语句从英文的字面意义上理解就是"根据(by)一定的规则进行分组(Group)". 作用:通过一定的规则将一个数据集划分成若干个小的区域,然后针对若干个小区域进行数据处理. 注意:group by 是先排序后分组! 举例说明:如果要用到group by 一般用到的就是"每"这个字, 例如现在有一个这样的需求:查询每个部门有多少人.就要用到分组的技术 select DepartmentID as '部门名称',

  • jQuery中even选择器的定义和用法

    本文实例讲述了jQuery中even选择器的定义和用法.分享给大家供大家参考.具体分析如下: 此选择器匹配所有索引值为偶数的元素,从0开始计数. 语法结构: 复制代码 代码如下: $(":even") 此选择器一般也要和其他选择器配合使用,比如类选择器.元素选择器等等. 例如: 复制代码 代码如下: $("li:even)").css("color","green") 以上代码是将li元素集合中索引为偶数的li中的字体颜色设置

  • JS中正则表达式全局匹配模式 /g用法详解

    本文章来详细介绍js中正则表达式的全局匹配模式 /g用法,代码如下: var str = "123#abc"; var re = /abc/ig; console.log(re.test(str)); //输出ture console.log(re.test(str)); //输出false console.log(re.test(str)); //输出ture console.log(re.test(str)); //输出false 在创建正则表达式对象时如果使用了"g&q

  • ThinkPHP中RBAC类的四种用法分析

    本文实例讲述了ThinkPHP中RBAC类的四种用法.分享给大家供大家参考.具体方法如下: 第一类:放在登陆控制器的登陆操作中 1.RBAC::authenticate(); 用于在用户表中查找表单提交的用户名的数据,实质上就是一条用户表查寻语句: 复制代码 代码如下: return M(modle)->where(array)->find(); 这个操作有两个参数 a.array()数组的写法及作用和表查寻数组一样: 复制代码 代码如下: array('字段'=>'值','字段'=&g

  • PHP中__FILE__、dirname与basename用法实例分析

    本文实例讲述了PHP中__FILE__.dirname与basename用法.分享给大家供大家参考.具体方法如下: 在php中__FILE__当前运行文件的完整路径和文件名,如果用在被包含文件中,则返回被包含的文件名,这是一个魔法变量(预定义常量),我们可以通用dirname与basename来获取文件目录或文件名. 一.__FILE__与dirname(__FILE__)与basename(__FILE__)使用: 通常在配置文件路径的时候用dirname(__FILE__)是非常有效的方法,

随机推荐