使用TPL取回Task中的运行结果的三种方式

概念:TPL( Task Parallel Library) 任务并行库

使用Task类执行多线程操作要比直接使用自己手工创建Thread效率高很多。

默认情况下,TPL使用线程池中的线程执行Task,但是工作结束之后,调用者线程怎么取回执行线程的工作结果呢?

这里有三种方法:

1.使用经典的线程同步手段:

可以使用线程同步对象。比如ManualResetEvent

在任务方法中设置ManualResetEvent状态为Signaled

调用者示例代码:

示例代码:

/// <summary>
        /// 用于保存处理结果的共享资源
        /// </summary>
        private static long result = 0;
        /// <summary>
        /// 用于通知启动任务的线程处理工作已完成
        /// </summary>
        static ManualResetEvent mre = new ManualResetEvent(false);
        static void Main(string[] args)
        {
            Action<object> taskMethod = (end) =>
            {
                long sum = 0;
                for (int i = 1; i < (int) end; i++)
                    sum += i;
                //保存处理结果(使用Interlocked实现原子操作,无需加锁)
                Interlocked.Exchange(ref result, sum);
                //通知调用者,工作已经完成,可以取回结果了
                mre.Set();
            };
            //启动异步任务
            Task tsk = new Task(taskMethod,1000000);
            tsk.Start();
            //等待并行处理的完成已取回结果
            mre.WaitOne();
            Console.WriteLine("程序运行结果为{0}",Program.result);
            Console.ReadKey();
        }

这种方法混杂了TPL与传统多线程开发方式,不推荐使用

2.使用Task<T>,Result属性

示例代码:

static void Main(string[] args)
        {
            Func<object, long> del = (end) =>
            {
                long sum = 0;
                for (int i = 1; i < (int) end; i++)
                    sum += i;
                return sum;
            };
            Task<long> tsk = new Task<long>(del,100000);
            tsk.Start();
            Console.WriteLine("程序运行结果为{0}",tsk.Result);
            Console.ReadKey();
        }

这种编程方式代码简洁,开发中可用,但是调用者线程必须阻塞等待任务结束。不适合在服务端应用中使用

3.基于回调模式的结果取回

TPL中有一个ContinueWith()方法,可用于创建前赴后继的工作任务

这里调用者线程不是阻塞等待的。适合在服务端应用程序中使用。

示例代码

static void Main(string[] args)
        {
            Func<object, long> ProcessData = (end) =>
            {
                long sum = 0;
                for (int i = 1; i < (int)end; i++)
                {
                    sum += i;
                    throw new DivideByZeroException();
                }
                return sum;
            };
            //用于取回处理结果的函数
            Action<Task<long>> GetResult = (finishedTask) =>
            {
                //依据任务状态,决定后继处理工作
                if (finishedTask.IsFaulted)
                    Console.WriteLine("任务在执行时发生异常:{0}", finishedTask.Exception);
                else
                    Console.Write("程序运行结果为{0}", finishedTask.Result);
            };

            //创建并行处理数据的任务对象
            Task<long> tskProcess = new Task<long>(ProcessData, 1000000);

            //当数据处理结束时,自动启动下一个工作任务,取回上一任务的处理结果
            Task tskGetResult = tskProcess.ContinueWith(GetResult);

            //开始并行处理数据……
            tskProcess.Start();

            Console.ReadKey();
        }

原文地址:https://www.cnblogs.com/c-supreme/p/8909058.html

时间: 2024-10-22 09:53:15

使用TPL取回Task中的运行结果的三种方式的相关文章

cocos2d 中加入显示文字的三种方式(CCLabelTTF 、CCLabelBMFont 和CCLabelAtlas)

在 cocos2d 中有三个类能够在层或精灵中加入文字: CCLabelTTF CCLabelBMFont CCLabelAtlas      CCLabelTTF CCLabelTTF 每次调用 setString (即改变文字)的时候,一个新的OPENGL 纹理将会被创建..这意味着setString 和创建一个新的标签一样慢. 所以,当你须要频繁的更新它们的时候,尽可能的不用去使用标签对象.  而应该使用CCLabelAtlas或者是CCLabelBMFont. OK, 看下它的用法 CC

JSP中设置Session有效时间的三种方式

JSP中设置Session有效时间的三种方式 2010-08-03 10:02:49|  分类: Java Web|举报|字号 订阅 (1)在主页面或者公共页面中加入: HttpSession session=request.getSession(true); session.setMaxInactiveInterval(900);参数900单位是秒,即在没有活动15分钟后,session将失效.这里要注意这个session设置的时间是根据服务器来计算的,而不是客户端.所以如果是在调试程序,应该

.net 中dapper实现事务的三种方式总结

.net 中实现事务查询的三种方式 1.TransactionScope  通过创建TransactionScope  对象然后包裹connection对象执行相关查询操作,完成 此种方式可以用于分布式事务操作,当链接不同数据库时,通过简单配置可以实现不同数据库的事务操作,当使用单机查询时(即只有一个数据库并且与应用服务器在同一台电脑时,不需要做额外配置) 2.通过connection 对象 BeginTransaction方法 创建,然后执行查询方法是都带上 transaction对象来实现

spring中创建bean对象的三种方式以及作用范围

时间:2020/02/02 一.在spring的xml配置文件中创建bean对象的三种方式: 1.使用默认构造函数创建.在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数函数,则对象无法创建. <bean id="one" class="sdnu.machi.one"></bean> 如果one.class中没有默认构造函数则会报

Linux中设置服务自启动的三种方式

有时候我们需要Linux系统在开机的时候自动加载某些脚本或系统服务 主要用三种方式进行这一操作: ln -s                       在/etc/rc.d/rc*.d目录中建立/etc/init.d/服务的软链接(*代表0-6七个运行级别之一) chkonfig                命令行运行级别设置 ntsysv                   伪图形运行级别设置 注意:1.这三种方式主要用于以redhat为基础的发行版 2.如果还不知道运行级别是什么,那么最

[转]Linux中设置服务自启动的三种方式

from:http://www.cnblogs.com/nerxious/archive/2013/01/18/2866548.html 有时候我们需要Linux系统在开机的时候自动加载某些脚本或系统服务 主要用三种方式进行这一操作: ln -s                       在/etc/rc.d/rc*.d目录中建立/etc/init.d/服务的软链接(*代表0-6七个运行级别之一) chkonfig                命令行运行级别设置 ntsysv        

1在html中添加js代码的三种方式

1.第一种方式:在时间句柄后太假js代码: 例如浏览器弹出对话框; 1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 2 "http://www.w3.org/TR/html4/loose.dtd"> 3 <html> 4 <head> 5 <meta http-equiv="Content-Type" content=&qu

(转)Linux中设置服务自启动的三种方式

有时候我们需要Linux系统在开机的时候自动加载某些脚本或系统服务 主要用三种方式进行这一操作: ln -s                       在/etc/rc.d/rc*.d目录中建立/etc/init.d/服务的软链接(*代表0-6七个运行级别之一) chkonfig                命令行运行级别设置 ntsysv                   伪图形运行级别设置 注意:1.这三种方式主要用于以redhat为基础的发行版 2.如果还不知道运行级别是什么,那么最

Java中 实现多线程成的三种方式(继承,实现,匿名内部类)

------------------------------------------------------------------------------------------------------------ /** 第一种方式:继承Thread类 *             1. 定义一个类,然后让该类继承Thread类 *             2. 重写run方法 *             3. 创建定义的这个类的对象 *             4. 启动线程 */ //继承