C#多线程编程笔记(4.2)-组合任务(Task)

近来在学习Eugene Agafonov编写的《C#多线程编程实战》(译),做些笔记也顺便分享一下^-^ 

本节将展示如何设置相互依赖的任务。我们将学习如何创建一个任务,使其在父任务完成后才会被运行。

using System;
using System.Threading.Tasks;
using System.Threading;

namespace 组合任务
{
    class Program
    {
        static void Main(string[] args)
        {
            var firstTask = new Task<int>(() => TaskMethod("First Task", 3));
            var secondTask = new Task<int>(() => TaskMethod("Second Task", 2));

            firstTask.ContinueWith(t => Console.WriteLine("The first answer is {0}.Thread id: {1},is thread pool thread: {2}",
                                                            t.Result,
                                                            Thread.CurrentThread.ManagedThreadId,
                                                            Thread.CurrentThread.IsThreadPoolThread
                                                          ),TaskContinuationOptions.OnlyOnRanToCompletion);
            firstTask.Start();
            secondTask.Start();

            Thread.Sleep(TimeSpan.FromSeconds(4));

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

            continuation.GetAwaiter().OnCompleted(
                () => Console.WriteLine("Cotinuation Task Completed!" +
                "Thread id {0},is thread pool thread: {1}",
                Thread.CurrentThread.ManagedThreadId,
                Thread.CurrentThread.IsThreadPoolThread));

            Thread.Sleep(TimeSpan.FromSeconds(2));
            Console.WriteLine();

            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();

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

            //Thread.Sleep(TimeSpan.FromSeconds(10));
            Console.ReadKey();
        }

        static int TaskMethod(string name,int seconds)
        {
            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(TimeSpan.FromSeconds(seconds));
            return 42 * seconds;
        }
    }
}

程序运行结果如下:


当主程序启动时,我们创建了两个任务,并为第一个任务设置了一个后续操作(continuation,一个代码块,会在当前任务完成后运行)。然后启动这两个任务并等待4秒,这个时间足够两个任务完成。然后给第二个任务运行另一个后续操作,并通过指定TaskContinuationOptions.ExecuteSynchronously选项来尝试同步执行该后续操作。如果后续操作耗时非常短暂,使用以上方式是非常有用的,因为放置在主线程中运行比放置在线程池中运行要快。可以实现这一点是因为第二个任务恰好在那刻完成。如果注释掉4秒的Thread.Sleep方法,将会看到该代码被放置到线程池中,这是因为还未从之前的任务中得到结果。

最后我们为之前的后续操作也定义了一个后续操作,但这里使用了一个稍微不同的方式,即使用了新的GetAwaiter和OnCompleted方法,这些方法是C#5.0语言中异步机制中的方法。

主逻辑的最后部分与父子线程有关,我们创建了一个新任务,当运行该任务时,通过提供一个TaskCreationOptions.AttachedToParent选项来运行一个所谓的子任务。子任务必须在父任务运行时创建,并正确的附加给父任务。

这意味着只有所有子任务结束工作,父任务才会完成。通过提供一个TaskContinuationOptions选项也可以给在子任务上运行后续操作。该后续操作也会影响父任务,并且直到最后一个子任务结束它才会运行完成。

猜你喜欢

转载自blog.csdn.net/qq_35445058/article/details/80810946