使用任务并行库-组合任务

  本节将展示如何设置相互依赖的任务。我们将学习如何创建一个任务,使其在父任务完成后才会被运行。另外,将探寻为非常短暂的任务节省线程开销的可能性。

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));//主线程----等待上面两个任务的完成,4秒应该足够执行完上面2个操作
     //如果注释掉以上语句,主线程直接执行下面的语句,则第二个任务的后续操作会放到线程池中执行

/* 设置第二个任务的后续操作,TaskContinuationOptions.ExecuteSynchronously设置为同步执行,
* 如果上面不等待4秒,后续操作将放到线程池中等待第二个任务执行完成后执行;如果等待4秒,即等待
* 第二个任务的完成,则后续操作被放到主线程中执行。因为后续操作非常短暂,所以放到主线程中比放到
* 线程池中运行快。
* TaskContinuationOptions.OnlyOnRanToCompletion指示第二个任务完成后才会安排后续任务。
*/

        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(//给continuation任务继续安排后续任务
            () => Console.WriteLine("Continuation Task Completed! Thread id {0}, is thread pool thread: {1}",
                Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread));
 
        Thread.Sleep(TimeSpan.FromSeconds(2));
        Console.WriteLine();
 
    //以下为父子任务线程有关
    /* 子任务必须在父任务运行时创建,并且正确的附加给父任务!
    * TaskContinuationOptions.AttachedToParent把子任务添加到父任务,只有所有子任务都完成,父任务才能完成。
    */
firstTask
= new Task<int>(() =>//创建新任务 {
       //通过提供AttachedToParent选项来来运行一个所谓的子任务
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)); } 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; } }