C# 异步编程3 TPL Task 异步程序开发

2017-09-12 19:23:15来源:cnblogs.com作者:DW039人点击

分享

.Net在Framework4.0中增加了任务并行库,对开发人员来说利用多核多线程CPU环境变得更加简单,TPL正符合我们本系列的技术需求。因TPL涉及内容较多,且本系列文章为异步程序开发,所以本文并未涉及TPL全部内容。后续会写一个TPL系列的Blog,各位朋友可以关注一下。

TASK

TPL的基础Task,Task是TPL并行编程的最小单元,即表示一个异步操作。利用Task进行异步编程非常简单:

        static void Main(string[] args)        {            BaseTaskDemo();            //BaseTaskDemo2();//两者效果相同            Console.WriteLine(String.Format("Main 线程:{0},获取异步执行结果:{1}", Thread.CurrentThread.ManagedThreadId,task.Result));            Console.ReadLine();        }        private static void BaseTaskDemo()        {            var task = new Task(() => {                Thread.Sleep(2000);                Console.WriteLine(String.Format("Task 线程:{0}", Thread.CurrentThread.ManagedThreadId));            });            task.Start();        }        private static void BaseTaskDemo2()        {            var task = Task.Run(() =>            {                Thread.Sleep(2000);                Console.WriteLine(String.Format("Task 线程:{0}", Thread.CurrentThread.ManagedThreadId));            });        }

程序说明:

1、new Task(Action)创建一个异步任务,参数Action是异步任务要执行的委托对象

2、task.Start()启动异步任务的执行

3、Task.Run(Action)等效于1、2的组合

上面的示例程序实现了异步操作,但主线程无法获知异步任务完成与否。为获取Task的执行结果,上面的程序进行如下修改:

        static void Main(string[] args)        {            var task = TaskForResult();            Console.WriteLine(String.Format("Main 线程:{0}", Thread.CurrentThread.ManagedThreadId));            task.Wait();            if (task.IsCompleted)                Console.WriteLine(String.Format("获取异步执行结果:{0}", task.Result));            Console.ReadLine();        }        private static Task<int> TaskForResult()        {            var task = Task.Run(()=> {                Thread.Sleep(2000);                Console.WriteLine(string.Format("Task 线程:{0},Task执行完成。", Thread.CurrentThread.ManagedThreadId));                return 10;            });            return task;        }

程序说明:

1、下面代码的原型为Task.Run(Func<int>),Run的参数不再是Action,因为在该任务中我们要返回一个int值,所以应该使用Run(Func<T>)这个重载。

var task = Task.Run(()=> {    Thread.Sleep(2000);    Console.WriteLine(string.Format("Task 线程:{0},Task执行完成。", Thread.CurrentThread.ManagedThreadId));    return 10;});

2、主线程中调用task.Wait()时,主线程将一直等待异步任务完成或被取消。

3、task.IsCompleted属性用于判断异步任务是否完成

4、task.Result获取异步任务的执行结果(返回值)

上面的示例程序已经实现了主线程获取异步程序的状态及返回值,但如果异步程序非常耗时,则存在主线程需要临时取消耗时异步程序执行的功能。为了满足上述要求,程序可做如下调整:

        static void Main(string[] args)        {            CancellationTokenSource tokenSource = new CancellationTokenSource(5000);            var task = TaskForResult2(tokenSource);            Console.WriteLine(String.Format("Main 线程:{0}", Thread.CurrentThread.ManagedThreadId));            Console.WriteLine(String.Format("Main 线程:{0},获取异步执行结果:{1}", Thread.CurrentThread.ManagedThreadId, task.Result));            Console.ReadLine();        }        private static Task<int> TaskForResult2(CancellationTokenSource tokenSource)        {            var task = Task.Run(() =>            {                Thread.Sleep(10000);                if (!tokenSource.IsCancellationRequested)                {                    Console.WriteLine(String.Format("Task 线程:{0},任务1执行完成。", Thread.CurrentThread.ManagedThreadId));                    return 10;                }                else                {                    return -1;                }            }, tokenSource.Token);            return task;        }

程序说明:

1、CancellationTokenSource提供任务取消消息,构造参数 5000 表示CancellationTokenSource在发出5s后超时并取消

2、在Task的委托内部 tokenSource.IsCancellationRequested 获取取消标记

3、task.Result会隐式调用Wait()方法

如果异步Task在执行过程中出现异常,则需要对发生的异常做出响应:

        static void Main(string[] args)        {            CancellationTokenSource tokenSource = new CancellationTokenSource(5000);            var task = TaskForResult2(tokenSource);            Console.WriteLine(String.Format("Main 线程:{0}", Thread.CurrentThread.ManagedThreadId));            try            {                //task.Wait();                Console.WriteLine(String.Format("Main 线程:{0},获取异步执行结果:{1}", Thread.CurrentThread.ManagedThreadId, task.Result));            }            catch (AggregateException ex)            {            }            Console.ReadLine();        }        private static Task<int> TaskForResult2(CancellationTokenSource tokenSource)        {            var task = Task.Run(() =>            {                Thread.Sleep(1000);                if (!tokenSource.IsCancellationRequested)                {                    throw new Exception("抛出异常");                }                else                {                    return -1;                }            }, tokenSource.Token);            return task;        }

程序说明:

1、在Task中引发的异常需要在 task.Wait()或task.Result时捕获

写在后面:Task的功能远不止上述这些,如Task多任务串行、TaskFactory、Paralle等知识非常有趣和重要。如果你感兴趣的话,可以关注本人后续TPL的文章。

 

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台