相关文章推荐
深沉的筷子  ·  Modes de chiffrement ...·  4 天前    · 
酷酷的火龙果  ·  SubtleCrypto: ...·  3 周前    · 
腹黑的足球  ·  BETWEEN start_time ...·  1 月前    · 
温柔的炒粉  ·  xcode - Unable to ...·  9 月前    · 
博学的枇杷  ·  Laravel whereHas and ...·  1 年前    · 
灰常酷的柳树  ·  Cross-Origin Read ...·  1 年前    · 
文武双全的企鹅  ·  bash - Only mkdir if ...·  1 年前    · 
public ref class Task : IAsyncResult
public ref class Task : IAsyncResult, IDisposable
public class Task : IAsyncResult
public class Task : IAsyncResult, IDisposable
type Task = class
    interface IAsyncResult
type Task = class
    interface IAsyncResult
    interface IDisposable
Public Class Task
Implements IAsyncResult
Public Class Task
Implements IAsyncResult, IDisposable
Object

Task 表示不返回值且通常异步执行的单个操作。 Task 对象是.NET Framework 4 中首次引入的 基于任务的异步模式 的核心组件之一。 由于对象执行 Task 的工作通常在线程池线程上异步执行,而不是在主应用程序线程上同步执行,因此可以使用 Status 属性以及 IsCanceled IsCompleted IsFaulted 属性来确定任务的状态。 大多数情况下,lambda 表达式用于指定任务要执行的工作。

对于返回值的操作,请使用 Task<TResult> 类。

本部分内容:

任务实例化示例
创建和执行任务
分离任务创建和执行
等待一个或多个任务完成
任务和区域性
面向调试器开发人员

任务实例化

以下示例创建并执行四个任务。 三个任务执行名为 Action<T> action 的委托,该委托接受类型 Object 为 的参数。 第四个任务 ( Action 委托) 执行 lambda 表达式,该委托在对任务创建方法的调用中内联定义。 每个任务都以不同的方式实例化并运行:

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

  • 任务 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 demonstrate 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 Imports System.Threading Imports System.Threading.Tasks Module Example Public Sub Main() Dim action As Action(Of Object) = Sub(obj As Object) Console.WriteLine("Task={0}, obj={1}, Thread={2}", Task.CurrentId, obj, Thread.CurrentThread.ManagedThreadId) End Sub ' Construct an unstarted task Dim t1 As New Task(action, "alpha") ' Construct a started task Dim t2 As Task = Task.Factory.StartNew(action, "beta") ' Block the main thread to demonstrate 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. Dim taskData As String = "delta" Dim t3 As Task = Task.Run(Sub() Console.WriteLine("Task={0}, obj={1}, Thread={2}", Task.CurrentId, taskData, Thread.CurrentThread.ManagedThreadId) End Sub) ' Wait for the task to finish. t3.Wait() ' Construct an unstarted task Dim t4 As 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() End Sub End Module ' 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=3 ' Task=3, obj=delta, Thread=3 ' Task=4, obj=gamma, Thread=1

    创建和执行任务

    Task 可以通过多种方式创建实例。 从 .NET Framework 4.5 开始,最常见的方法是调用静态 Run 方法。 方法 Run 提供了一种使用默认值启动任务的简单方法,而无需其他参数。 以下示例使用 Run(Action) 方法启动循环任务,然后显示循环迭代次数:

    using System; using System.Threading.Tasks; public class Example public static async Task Main() await Task.Run( () => { // Just loop. int ctr = 0; for (ctr = 0; ctr <= 1000000; ctr++) Console.WriteLine("Finished {0} loop iterations", ctr); // The example displays the following output: // Finished 1000001 loop iterations Imports System.Threading.Tasks Module Example Public Sub Main() Dim t As Task = Task.Run(Sub() ' Just loop. Dim ctr As Integer = 0 For ctr = 0 to 1000000 Console.WriteLine("Finished {0} loop iterations", End Sub) t.Wait() End Sub End Module ' The example displays the following output: ' Finished 1000001 loop iterations

    另一种方法是静态 TaskFactory.StartNew 方法,也是在 .NET Framework 4 中启动任务的最常见方法。 属性 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 Imports System.Threading.Tasks Module Example Public Sub Main() Dim t As Task = Task.Factory.StartNew(Sub() ' Just loop. Dim ctr As Integer = 0 For ctr = 0 to 1000000 Console.WriteLine("Finished {0} loop iterations", End Sub) t.Wait() End Sub End Module ' The example displays the following output: ' Finished 1000001 loop iterations

    有关更完整的示例,请参阅 基于任务的异步编程

    分离任务创建和执行

    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 Imports System.Threading Imports System.Threading.Tasks Module Example Public Sub Main() ' Wait on a single task with no timeout specified. Dim taskA = Task.Run( Sub() Thread.Sleep(2000)) Console.WriteLine("taskA Status: {0}", taskA.Status) taskA.Wait() Console.WriteLine("taskA Status: {0}", taskA.Status) Catch e As AggregateException Console.WriteLine("Exception in taskA.") End Try End Sub End Module ' 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. Imports System.Threading Imports System.Threading.Tasks Module Example Public Sub Main() ' Wait on a single task with a timeout specified. Dim taskA As Task = Task.Run( Sub() Thread.Sleep(2000)) taskA.Wait(1000) ' Wait for 1 second. Dim completed As Boolean = taskA.IsCompleted Console.WriteLine("Task.Completed: {0}, Status: {1}", completed, taskA.Status) If Not completed Then Console.WriteLine("Timed out before task A completed.") End If Catch e As AggregateException Console.WriteLine("Exception in taskA.") End Try End Sub End Module ' The example displays the following output: ' Task A completed: False, Status: Running ' Timed out before task A completed.

    还可以通过调用 Wait(CancellationToken) Wait(Int32, CancellationToken) 方法提供取消令牌。 如果在执行方法时令牌的 IsCancellationRequested 属性为 true 或 变为 true ,则 该方法将 OperationCanceledException Wait 引发 。

    在某些情况下,你可能希望等待一系列执行任务中的第一个完成,但不关心它是哪个任务。 为此,可以调用 方法的重载 Task.WaitAny 之一。 以下示例创建三个任务,每个任务都按随机数生成器确定的间隔休眠。 方法 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 Imports System.Threading Imports System.Threading.Tasks Module Example Public Sub Main() Dim tasks(2) As Task Dim rnd As New Random() For ctr As Integer = 0 To 2 tasks(ctr) = Task.Run( Sub() Thread.Sleep(rnd.Next(500, 3000))) Dim index As Integer= Task.WaitAny(tasks) Console.WriteLine("Task #{0} completed first.", tasks(index).Id) Console.WriteLine() Console.WriteLine("Status of all tasks:") For Each t in tasks Console.WriteLine(" Task #{0}: {1}", t.Id, t.Status) Catch e As AggregateException Console.WriteLine("An exception occurred.") End Try End Sub End Module ' 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 方法等待所有一系列任务完成。 以下示例创建 10 个任务,等待全部 10 个任务完成,然后显示其状态。

    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 Imports System.Threading Imports System.Threading.Tasks Module Example Public Sub Main() ' Wait for all tasks to complete. Dim tasks(9) As Task For i As Integer = 0 To 9 tasks(i) = Task.Run( Sub() Thread.Sleep(2000) ) Task.WaitAll(tasks) Catch ae As AggregateException Console.WriteLine("One or more exceptions occurred: ") For Each ex In ae.Flatten().InnerExceptions Console.WriteLine(" {0}", ex.Message) End Try Console.WriteLine("Status of completed tasks:") For Each t in tasks Console.WriteLine(" Task #{0}: {1}", t.Id, t.Status) End Sub End Module ' 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 个任务,其中 3 个正常完成,其中 3 个引发异常。 在其余六个任务中,有 3 个在开始前取消,3 个任务在执行时取消。 异常在方法调用中 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 Imports System.Threading Imports System.Threading.Tasks Module Example Public Sub Main() ' Create a cancellation token and cancel it. Dim source1 As New CancellationTokenSource() Dim token1 As CancellationToken = source1.Token source1.Cancel() ' Create a cancellation token for later cancellation. Dim source2 As New CancellationTokenSource() Dim token2 As CancellationToken = source2.Token ' Create a series of tasks that will complete, be cancelled, ' timeout, or throw an exception. Dim tasks(11) As Task For i As Integer = 0 To 11 Select Case i Mod 4 ' Task should run to completion. Case 0 tasks(i) = Task.Run( Sub() Thread.Sleep(2000)) ' Task should be set to canceled state. Case 1 tasks(i) = Task.Run( Sub() Thread.Sleep(2000), token1) Case 2 ' Task should throw an exception. tasks(i) = Task.Run( Sub() Throw New NotSupportedException() End Sub) Case 3 ' Task should examine cancellation token. tasks(i) = Task.Run( Sub() Thread.Sleep(2000) If token2.IsCancellationRequested token2.ThrowIfCancellationRequested() End If Thread.Sleep(500) End Sub, token2) End Select Thread.Sleep(250) source2.Cancel() Task.WaitAll(tasks) Catch ae As AggregateException Console.WriteLine("One or more exceptions occurred:") For Each ex in ae.InnerExceptions Console.WriteLine(" {0}: {1}", ex.GetType().Name, ex.Message) End Try Console.WriteLine() Console.WriteLine("Status of tasks:") For Each t in tasks Console.WriteLine(" Task #{0}: {1}", t.Id, t.Status) If t.Exception IsNot Nothing Then For Each ex in t.Exception.InnerExceptions Console.WriteLine(" {0}: {1}", ex.GetType().Name, ex.Message) End If End Sub End Module ' 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 4.6 之前.NET Framework版本的应用,任务的区域性是执行任务的线程的区域性。 有关详细信息,请参阅主题中的 CultureInfo “区域性和基于任务的异步操作”部分。

    应用商店应用遵循设置和获取默认区域性Windows 运行时。

    面向调试器开发人员

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

  •