Framework4 task

Task 可以多种方式创建实例。 最常用的方法,它位于开头 .NET Framework 4.5, ,是调用静态 Run 方法。 Run 方法提供了简单的方法来启动任务使用默认值,并且无需额外的参数。 下面的示例使用 Run(Action) 方法来启动循环,然后显示循环迭代数的任务︰

 
using System;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      Task t = Task.Run( () => {
                                  // Just loop.
                                  int ctr = 0;
                                  for (ctr = 0; ctr <= 1000000; ctr++)
                                  {}
                                  Console.WriteLine("Finished {0} loop iterations",
                                                    ctr);
                               } );
      t.Wait();
   }
}
// The example displays the following output:
//        Finished 1000001 loop iterations

替代方法,并启动任务的最常见方法 .NET Framework 4, ,是静态 TaskFactory.StartNew 方法。 Task.Factory 属性将返回 TaskFactory 对象。重载 TaskFactory.StartNew 方法,你可以指定要传递给任务创建选项和任务计划程序参数。 下面的示例使用 TaskFactory.StartNew 方法来启动任务。 它是功能上等效于在前面的示例代码。

 
using System;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      Task t = Task.Factory.StartNew( () => {
                                  // Just loop.
                                  int ctr = 0;
                                  for (ctr = 0; ctr <= 1000000; ctr++)
                                  {}
                                  Console.WriteLine("Finished {0} loop iterations",
                                                    ctr);
                               } );
      t.Wait();
   }
}
// The example displays the following output:
//        Finished 1000001 loop iterations

有关更完整示例,请参阅 Task Parallelism (Task Parallel Library)

Task 类还提供了构造函数对任务进行初始化,但的未计划的执行。 出于性能原因, Task.Run 或 TaskFactory.StartNew 方法是用于创建和计划计算的任务的首选的机制,但对于创建和计划必须分开的方案,您可以使用的构造函数,然后调用 Task.Start 方法来计划任务,以在稍后某个时间执行。

因为任务通常运行以异步方式在线程池线程上,创建并启动任务的线程将继续执行,一旦该任务已实例化。 在某些情况下,当调用线程的主应用程序线程,该应用程序可能会终止之前任何任务实际开始执行。 其他情况下,应用程序的逻辑可能需要调用线程继续执行,仅当一个或多个任务执行完毕。 您可以同步调用线程的执行,以及异步任务它启动通过调用 Wait 方法来等待要完成的一个或多个任务。

若要等待完成一项任务,可以调用其 Task.Wait 方法。 调用 Wait 方法将一直阻塞调用线程直到单一类实例都已完成执行。

下面的示例调用无参数 Wait() 方法,以无条件地等待,直到任务完成。 该任务通过调用来模拟工作 Thread.Sleep 方法进入睡眠状态两秒钟。

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

class Program
{
    static Random rand = new Random();

    static void Main()
    {
        // Wait on a single task with no timeout specified.
        Task taskA = Task.Run( () => Thread.Sleep(2000));
        Console.WriteLine("taskA Status: {0}", taskA.Status);
        try {
          taskA.Wait();
          Console.WriteLine("taskA Status: {0}", taskA.Status);
       } 
       catch (AggregateException) {
          Console.WriteLine("Exception in taskA.");
       }   
    }    
}
// The example displays output like the following:
//     taskA Status: WaitingToRun
//     taskA Status: RanToCompletion

您可以有条件地等待任务完成。 Wait(Int32) 和 Wait(TimeSpan) 方法阻止调用线程,直到任务完成或超时间隔结束,具体取决于第一个。 由于下面的示例将启动一个任务,它在睡眠两秒钟,但定义的一秒的超时值,调用线程受到阻止,直到超时到期和之前的任务已完成执行。

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

public class Example
{
   public static void Main()
   {
      // Wait on a single task with a timeout specified.
      Task taskA = Task.Run( () => Thread.Sleep(2000));
      try {
        taskA.Wait(1000);       // Wait for 1 second.
        bool completed = taskA.IsCompleted;
        Console.WriteLine("Task A completed: {0}, Status: {1}",
                         completed, taskA.Status);
        if (! completed)
           Console.WriteLine("Timed out before task A completed.");                 
       }
       catch (AggregateException) {
          Console.WriteLine("Exception in taskA.");
       }   
   }
}
// The example displays output like the following:
//     Task A completed: False, Status: Running
//     Timed out before task A completed.

你也可以通过调用提供一个取消标记 Wait(CancellationToken) 和 Wait(Int32, CancellationToken) 方法。 如果该令牌的IsCancellationRequested 属性是 true, ,取消等待; 如果它变为 true 时 Wait 方法终止。

在某些情况下,您可能想要等待的执行的任务的一系列的第一个完成,但不是任务它的关注。 出于此目的,您可以调用的重载之一 Task.WaitAll方法。 下面的示例创建三个任务,其中每个休眠的随机数字生成器确定时间间隔。 WaitAny(Task[]) 方法等待第一个任务完成。 此示例随后显示所有三个任务的状态的信息。

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

public class Example
{
   public static void Main()
   {
      var tasks = new Task[3];
      var rnd = new Random();
      for (int ctr = 0; ctr <= 2; ctr++)
         tasks[ctr] = Task.Run( () => Thread.Sleep(rnd.Next(500, 3000)));

      try {
         int index = Task.WaitAny(tasks);
         Console.WriteLine("Task #{0} completed first.\n", tasks[index].Id);
         Console.WriteLine("Status of all tasks:");
         foreach (var t in tasks)
            Console.WriteLine("   Task #{0}: {1}", t.Id, t.Status);
      }
      catch (AggregateException) {
         Console.WriteLine("An exception occurred.");
      }
   }
}
// The example displays output like the following:
//     Task #1 completed first.
//     
//     Status of all tasks:
//        Task #3: Running
//        Task #1: RanToCompletion
//        Task #4: Running

您也可以等待所有任务的调用以完成一系列 WaitAll 方法。 下面的示例创建十个任务,等待所有十若要完成,然后显示其状态。

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

public class Example
{
   public static void Main()
   {
      // Wait for all tasks to complete.
      Task[] tasks = new Task[10];
      for (int i = 0; i < 10; i++)
      {
          tasks[i] = Task.Run(() => Thread.Sleep(2000));
      }
      try {
         Task.WaitAll(tasks);
      }
      catch (AggregateException ae) {
         Console.WriteLine("One or more exceptions occurred: ");
         foreach (var ex in ae.Flatten().InnerExceptions)
            Console.WriteLine("   {0}", ex.Message);
      }   

      Console.WriteLine("Status of completed tasks:");
      foreach (var t in tasks)
         Console.WriteLine("   Task #{0}: {1}", t.Id, t.Status);
   }
}
// The example displays the following output:
//     Status of completed tasks:
//        Task #2: RanToCompletion
//        Task #1: RanToCompletion
//        Task #3: RanToCompletion
//        Task #4: RanToCompletion
//        Task #6: RanToCompletion
//        Task #5: RanToCompletion
//        Task #7: RanToCompletion
//        Task #8: RanToCompletion
//        Task #9: RanToCompletion
//        Task #10: RanToCompletion

请注意,等待一个或多个任务完成时,则在正在运行的任务引发的任何异常传播调用的线程上 Wait 方法,如以下示例所示。 它将启动其中三个正常完成的 12 任务和三个哪些引发的异常。 剩余的六项任务,三个早于开始日期,将被取消,而三个将被取消时执行它们。 引发异常 WaitAll 方法调用,并且是处理 try/catch 块。

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

public class Example
{
   public static void Main()
   {
      // Create a cancellation token and cancel it.
      var source1 = new CancellationTokenSource();
      var token1 = source1.Token;
      source1.Cancel();
      // Create a cancellation token for later cancellation.
      var source2 = new CancellationTokenSource();
      var token2 = source2.Token;

      // Create a series of tasks that will complete, be cancelled, 
      // timeout, or throw an exception.
      Task[] tasks = new Task[12];
      for (int i = 0; i < 12; i++)
      {
          switch (i % 4) 
          {
             // Task should run to completion.
             case 0:
                tasks[i] = Task.Run(() => Thread.Sleep(2000));
                break;
             // Task should be set to canceled state.
             case 1:   
                tasks[i] = Task.Run( () => Thread.Sleep(2000),
                         token1);
                break;         
             case 2:
                // Task should throw an exception.
                tasks[i] = Task.Run( () => { throw new NotSupportedException(); } );
                break;
             case 3:
                // Task should examine cancellation token.
                tasks[i] = Task.Run( () => { Thread.Sleep(2000); 
                                             if (token2.IsCancellationRequested)
                                                token2.ThrowIfCancellationRequested();
                                             Thread.Sleep(500); }, token2);   
                break;
          }
      }
      Thread.Sleep(250);
      source2.Cancel();

      try {
         Task.WaitAll(tasks);
      }
      catch (AggregateException ae) {
          Console.WriteLine("One or more exceptions occurred:");
          foreach (var ex in ae.InnerExceptions)
             Console.WriteLine("   {0}: {1}", ex.GetType().Name, ex.Message);
       }   

      Console.WriteLine("\nStatus of tasks:");
      foreach (var t in tasks) {
         Console.WriteLine("   Task #{0}: {1}", t.Id, t.Status);
         if (t.Exception != null) {
            foreach (var ex in t.Exception.InnerExceptions)
               Console.WriteLine("      {0}: {1}", ex.GetType().Name,
                                 ex.Message);
         }
      }
   }
}
// The example displays output like the following:
//   One or more exceptions occurred:
//      TaskCanceledException: A task was canceled.
//      NotSupportedException: Specified method is not supported.
//      TaskCanceledException: A task was canceled.
//      TaskCanceledException: A task was canceled.
//      NotSupportedException: Specified method is not supported.
//      TaskCanceledException: A task was canceled.
//      TaskCanceledException: A task was canceled.
//      NotSupportedException: Specified method is not supported.
//      TaskCanceledException: A task was canceled.
//   
//   Status of tasks:
//      Task #13: RanToCompletion
//      Task #1: Canceled
//      Task #3: Faulted
//         NotSupportedException: Specified method is not supported.
//      Task #8: Canceled
//      Task #14: RanToCompletion
//      Task #4: Canceled
//      Task #6: Faulted
//         NotSupportedException: Specified method is not supported.
//      Task #7: Canceled
//      Task #15: RanToCompletion
//      Task #9: Canceled
//      Task #11: Faulted
//         NotSupportedException: Specified method is not supported.
//      Task #12: Canceled

有关基于任务的异步操作中的异常处理的详细信息,请参阅 异常处理(任务并行库)

从桌面应用程序面向 .NET Framework 4.6, ,创建并调用任务的线程的区域性将成为线程的上下文的一部分。 也就是说,无论此任务所执行为当前区域性,该任务的当前区域性是线程的调用线程的区域性。 对于之前的.NET Framework 目标版本的应用程序 .NET Framework 4.6, ,该任务的区域性是执行该任务时的线程的区域性。 有关详细信息,请参阅中的"区域性和基于任务的异步操作"部分 CultureInfo 主题。

System_CAPS_note说明

应用商店应用程序按照 Windows 运行时中设置和获取的默认区域性。

对于实现自定义调试器的开发人员而言,任务的几个内部和私有成员可能会很有用 (这可能会更改不同版本间)。 m_taskId 字段用作后备存储区Id 属性,但是访问此字段直接从调试器可能会通过该属性的 getter 方法访问相同的值比效率更高 ( s_taskIdCounter 计数器用于检索一项任务的下一个可用 ID)。 同样, m_stateFlags 字段存储当前的生命周期阶段的任务中,信息还可通过访问信息 Status 属性。 m_action 字段存储对任务的委托的引用和 m_stateObject 字段存储由开发人员传递给任务的异步状态。 最后,用于为分析堆栈帧的调试器 InternalWait 方法提供当某任务正在进入一个等待操作的潜在标记。

示例
 
 

下面的示例创建并执行四项任务。 三个任务执行 Action<T> 委托名为 action, ,这样便可以接受类型的参数 Object 第四个任务执行 lambda 表达式 ( Action 委托),它是以内联方式定义的任务创建方法调用中。 每个任务是实例化并以不同方式运行︰

  • 任务 t1 实例化时通过调用任务类构造函数,但通过调用会启动其 Start() 方法仅在任务后的 t2 已启动。

  • 任务 t2 会实例化并通过调用单个方法调用中启动 TaskFactory.StartNew(Action<Object>, Object) 方法。

  • 任务 t3 会实例化并通过调用单个方法调用中启动 Run(Action) 方法。

  • 任务 t4 上同步执行主线程通过调用 RunSynchronously() 方法。

因为任务 t4 以同步方式,执行其主应用程序线程上执行。 其余任务执行异步通常在一个或多个线程池线程上。

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

class Example
{
    static void Main()
    {
        Action<object> action = (object obj) =>
                                {
                                   Console.WriteLine("Task={0}, obj={1}, Thread={2}",
                                   Task.CurrentId, obj,
                                   Thread.CurrentThread.ManagedThreadId);
                                };

        // Create a task but do not start it.
        Task t1 = new Task(action, "alpha");

        // Construct a started task
        Task t2 = Task.Factory.StartNew(action, "beta");
        // Block the main thread to demonstate that t2 is executing
        t2.Wait();

        // Launch t1 
        t1.Start();
        Console.WriteLine("t1 has been launched. (Main Thread={0})",
                          Thread.CurrentThread.ManagedThreadId);
        // Wait for the task to finish.
        t1.Wait();

        // Construct a started task using Task.Run.
        String taskData = "delta";
        Task t3 = Task.Run( () => {Console.WriteLine("Task={0}, obj={1}, Thread={2}",
                                                     Task.CurrentId, taskData,
                                                      Thread.CurrentThread.ManagedThreadId);
                                   });
        // Wait for the task to finish.
        t3.Wait();

        // Construct an unstarted task
        Task t4 = new Task(action, "gamma");
        // Run it synchronously
        t4.RunSynchronously();
        // Although the task was run synchronously, it is a good practice
        // to wait for it in the event exceptions were thrown by the task.
        t4.Wait();
    }
}
// The example displays output like the following:
//       Task=1, obj=beta, Thread=3
//       t1 has been launched. (Main Thread=1)
//       Task=2, obj=alpha, Thread=4
//       Task=3, obj=delta, Thread=3
//       Task=4, obj=gamma, Thread=1
posted on 2017-08-15 14:02  西湖浪子  阅读(343)  评论(0)    收藏  举报