第4章:使用任务并行库

4.1 简介

  使用线程池可以使我们在减少并行度花销是节省操作系统资源。我们可以认为线程池是一个抽象层,其向程序员隐藏了使用线程的细节,使我们专心处理程序逻辑,而不是各种线程问题。

  任务并行库(Task Parallel Library,简称TPL),可被认为是线程池之上的有一个抽象层,对其程序员隐藏了与线程池交互的底层代码,并提供了更方便的细粒度的API。

  TPL的核心概念是任务。一个任务代表了一个异步操作,该操作可以通过多种方式运行,可以使用或不使用独立线程运行。

4.2 创建任务

任务1-4是放到线程池里的,所以任务的执行顺序是不确定的

        static void Main(string[] args)
        {
            var t1 = new Task(() => TaskMethod("Task 1"));
            var t2 = new Task(() => TaskMethod("Task 2"));
            t2.Start();
            t1.Start();
            // 任务
            Task.Run(() => TaskMethod("Task 3"));
            Task.Factory.StartNew(() => TaskMethod("Task 4"));
            Task.Factory.StartNew(() => TaskMethod("Task 5"),  TaskCreationOptions.LongRunning);
            Thread.Sleep(TimeSpan.FromSeconds(1));
            Console.Read();
        }

        static void TaskMethod(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}", name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
        }
View Code

4.3 使用任务执行基本的操作

任务1的task.Result会阻塞主线程,直到子线程完成。

任务2是同步任务,在主线程完成。

任务3没有阻塞主线程,只是在主线程循环打印任务状态。

   static void Main(string[] args)
        {
            TaskMethod("Main Thread Task");

            Task<int> task = CreateTask("Task 1");
            task.Start();
            int result = task.Result;
            Console.WriteLine("Result is:{0}", result);

            task = CreateTask("Task 2");
            task.RunSynchronously();
            result = task.Result;
            Console.WriteLine("Result is:{0}", result);

            task = CreateTask("Task 3");
            task.Start();

            while (!task.IsCompleted)
            {
                Console.WriteLine(task.Status);
                Thread.Sleep(TimeSpan.FromSeconds(0.5));
            }

            Console.WriteLine(task.Status);
            result = task.Result;
            Console.WriteLine("Result is:{0}", result);
            Console.Read();
        }

        static Task<int> CreateTask(string name)
        {
            return new Task<int>(() => TaskMethod(name));
        }

        static int TaskMethod(string name)
        {
            Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}", name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
            Thread.Sleep(2000);
            return 42;
        }
View Code

4.4 组合任务

 创建一个任务,使其在父任务完成后才会被运行,另外将探寻为非常短暂的任务节省线程开销的可能性。

    -- OnlyOnRanToCompletion:只有在firstTask完成之后执行

        static int TaskMethod(string name, int seconds)
        {
            Console.WriteLine($"Task {name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}. " +
                $"Is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}");
            Thread.Sleep(TimeSpan.FromSeconds(seconds));
            return seconds * 42;
        }
View Code
            var firstTask = new Task<int>(() => TaskMethod("First Task", 3));

            // OnlyOnRanToCompletion:只有在firstTask完成之后执行
            firstTask.ContinueWith(t => Console.WriteLine($"The first answer is {t.Result}.Thread id {Thread.CurrentThread.ManagedThreadId}," +
                    $"is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}"),
                   TaskContinuationOptions.OnlyOnRanToCompletion);
            firstTask.Start();
View Code

  -- TaskContinuationOptions.ExecuteSynchronously:如果没有Thread.Sleep(4),代码会在线程池中执行,因为之前的任务还没有执行完成。如果有Thread.Sleep(4),前面的任务已经执行完,所以会在主程序中执行,不会放到线程池里面来切换线程,这样更快。

            var secondTask = new Task<int>(() => TaskMethod("Second Task", 2));
            secondTask.Start();
            Thread.Sleep(TimeSpan.FromSeconds(4));

            Task continuation = secondTask.ContinueWith(t => Console.WriteLine($"The second answer is {t.Result}." +
                $"Thread id {Thread.CurrentThread.ManagedThreadId}, is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}"),
                TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously);

            continuation.GetAwaiter().OnCompleted(() => Console.WriteLine($"Continuation Task Completed! Thread is {Thread.CurrentThread.ManagedThreadId}," +
                $"is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}"));
            Thread.Sleep(TimeSpan.FromSeconds(2));
View Code

 -- TaskCreationOptions.AttachedToParent

            // 外部任务
            var firstTask = new Task<int>(() => {
                // 子任务
                var innerTask = Task.Factory.StartNew(() => TaskMethod("Second Task", 5), TaskCreationOptions.AttachedToParent);
                innerTask.ContinueWith(t => TaskMethod("Third Task", 2), TaskContinuationOptions.AttachedToParent);
                return TaskMethod("First Task", 2);
            });
            firstTask.Start();
View Code

4.7、实现取消选项 CancellationTokenSource.Cancel

        static int TaskMethod(string name, int seconds,CancellationToken token)
        {
            Console.WriteLine($"Task {name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}." +
                $"Is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}");
            for (int i = 0; i < seconds; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(1));
                if (token.IsCancellationRequested)
                {
                    return -1;
                }
            }
            return 42 * seconds;
        }
View Code

  -- 任务开始之前取消

            var cts = new CancellationTokenSource();
            var longTask = new Task<int>(() => TaskMethod("Task 1", 10, cts.Token), cts.Token);
            Console.WriteLine(longTask.Status);
            cts.Cancel();
            Console.WriteLine(longTask.Status);
            Console.WriteLine("First task has been cancelled before execution");
View Code

 -- 任务启动后取消

        static void Main(string[] args)
        {
            var cts = new CancellationTokenSource();
            var task = new Task<int>(() => TaskMethod("Task1", 10, cts.Token), cts.Token);
            task.Start();
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(0.5));
                Console.WriteLine(task.Status);
            }
            cts.Cancel();
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(TimeSpan.FromSeconds(0.5));
                Console.WriteLine(task.Status);
            }
            Console.Read();
        }
View Code

4.8、处理任务中的异常

        static int TaskMethod(string name, int seconds)
        {
            Console.WriteLine($"Task {name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}." +
                $"Is thread pool thread: {Thread.CurrentThread.IsThreadPoolThread}");
            Thread.Sleep(TimeSpan.FromSeconds(seconds));
            throw new Exception("Boom!");
        }
View Code

-- task.Result

        static void Main(string[] args)
        {
            Task<int> task;
            try
            {
                task = Task.Run(() => TaskMethod("Task1", 2));
                var result = task.Result;
                Console.WriteLine(result);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            Console.Read();
        }
View Code

-- task.GetAwaiter().GetResult()

        static void Main(string[] args)
        {
            Task<int> task;
            try
            {
                task = Task.Run(() => TaskMethod("Task2", 2));
                var result = task.GetAwaiter().GetResult();
                Console.WriteLine(result);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            Console.WriteLine("123");
            Console.Read();
        }
View Code

 -- 捕获异常,没有try catch

        static void Main(string[] args)
        {
            var t1 = new Task<int>(() => TaskMethod("Task 3", 3));
            var t2 = new Task<int>(() => TaskMethod("Task 4", 2));
            var complexTask = Task.WhenAll(t1, t2);
            var exceptionHandler = complexTask.ContinueWith(t => Console.WriteLine($"Exception caught {t.Exception}"), TaskContinuationOptions.OnlyOnFaulted);
            t1.Start();
            t2.Start();
            Console.Read();
        }
View Code

4.9、并行运行任务

        static int TaskMethod(string name, int seconds)
        {
            Console.WriteLine($"Task {name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}." +
                $"Is thread pool thread: {Thread.CurrentThread.IsThreadPoolThread}");
            Thread.Sleep(TimeSpan.FromSeconds(seconds));
            return 42 * seconds;
        }
View Code

-- Task.WhenAll

        static void Main(string[] args)
        {
            var t1 = new Task<int>(() => TaskMethod("Task 1", 3));
            var t2 = new Task<int>(() => TaskMethod("Task 2", 2));
            var complexTask = Task.WhenAll(t1, t2);
            var exceptionHandler = complexTask.ContinueWith(t => 
                Console.WriteLine($"The first answer is {t.Result[0]}, the second answer is {t.Result[1]}"), TaskContinuationOptions.OnlyOnRanToCompletion);
            t1.Start();
            t2.Start();
            Console.Read();
        }
View Code

-- Task.WhenAny

        static void Main(string[] args)
        {
            var tasks = new List<Task<int>>();
            for (int i = 0; i < 4; i++)
            {
                var counter = i;
                var task = new Task<int>(() => TaskMethod($"Task {counter}", counter));
                tasks.Add(task);
                task.Start();
            }
            while (tasks.Count > 0)
            {
                var completedTask = Task.WhenAny(tasks).Result;
                tasks.Remove(completedTask);
                Console.WriteLine($"A task has been completed with result {completedTask.Result}");
            }
            Console.Read();
        }
View Code

4.10、任务调度,UI交互

 

posted @ 2016-06-20 19:13  江境纣州  阅读(16)  评论(0编辑  收藏  举报