zoukankan      html  css  js  c++  java
  • C# 异步编程3 TPL Task 异步程序开发

    .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}", Thread.CurrentThread.ManagedThreadId));
                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的文章。

     
  • 相关阅读:
    开通博客园
    ios关键字
    FirstDay
    An example for pysnmp
    remove debug symbols to a seperate file
    qemu下通过gdb调试内核时 遇到 evaluation of this expression requires the program to have a function "malloc" 错误的解决办法
    关于常识与知识的思考
    基于Qemu在ubuntu上构建linux学习环境
    How to download prebuilt toolchain
    诡异的打印异常BUG
  • 原文地址:https://www.cnblogs.com/dw039/p/7507841.html
Copyright © 2011-2022 走看看