https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.tasks.task?redirectedfrom=MSDN&view=netframework-4.7.2
Task Class
定义
表示一个异步操作。
public class Task : IAsyncResult, IDisposable
- 继承
-
Task
- 派生
- 实现
注解
Task类的表示单个操作不会返回一个值,通常以异步方式执行。 Task 对象是一种的中心思想基于任务的异步模式首次引入.NET Framework 4 中。 因为由执行工作Task对象通常以异步方式执行线程池线程上而不是以同步方式在主应用程序线程中,可以使用Status属性,并将IsCanceled, IsCompleted,和IsFaulted属性,以确定任务的状态。 大多数情况下,lambda 表达式用于指定该任务所执行的工作量。
对于返回值的操作,您使用Task<TResult>类。
本节内容:
任务实例化示例
创建和执行任务
分离任务创建和执行
等待一个或多个任务完成
任务和区域性
调试程序开发人员
任务实例化
下面的示例创建并执行四个任务。 三个任务执行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 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
创建和执行任务
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
替代方法,并使用最常见方法启动任务.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类还提供了构造函数对任务进行初始化,但的未计划的执行。 出于性能原因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)方法阻止调用线程,直到任务完成或超时间隔结束,具体取决于第一个。 由于下面的示例将启动一个任务,休眠 2 秒,但定义的一秒的超时值,调用线程受到阻止,直到在超时到期之前, 已完成执行的任务。
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执行方法,该方法将引发OperationCanceledException。
在某些情况下,你可能想要等待执行任务的一系列的第一个问题以完成,但不是任务它的护理。 为此,可以调用的重载之一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主题。
备注
应用商店应用程序按照中设置和获取默认区域性的 Windows 运行时。
调试程序开发人员
对于开发人员实现自定义调试器,多个内部和私有成员的任务可能很有用 (这些可能会更改发行版本)。 m_taskId
字段用作后备存储Id属性,但是访问此字段直接从调试器可能会通过属性的 getter 方法访问相同的值比效率更高 (s_taskIdCounter
计数器是用于检索任务的下一个可用 ID)。 同样,m_stateFlags
字段存储的信息还可通过访问任务信息的当前生命周期阶段Status属性。 m_action
字段存储对任务的委托的引用和m_stateObject
字段存储由开发人员传递给任务的异步状态。 最后,对于分析堆栈帧的调试器InternalWait
方法提供一项任务时进入一个等待操作的潜在标记。
构造函数
Task(Action) |
使用指定的操作初始化新的 Task。 |
Task(Action, CancellationToken) |
使用指定的操作和 Task 初始化新的 CancellationToken。 |
Task(Action, CancellationToken, TaskCreationOptions) |
使用指定的操作和创建选项初始化新的 Task。 |
Task(Action, TaskCreationOptions) |
使用指定的操作和创建选项初始化新的 Task。 |
Task(Action<Object>, Object) |
使用指定的操作和状态初始化新的 Task。 |
Task(Action<Object>, Object, CancellationToken) |
使用指定的操作、状态和选项初始化新的 Task。 |
Task(Action<Object>, Object, CancellationToken, TaskCreationOptions) |
使用指定的操作、状态和选项初始化新的 Task。 |
Task(Action<Object>, Object, TaskCreationOptions) |
使用指定的操作、状态和选项初始化新的 Task。 |
属性
AsyncState |
获取在创建 Task 时提供的状态对象,如果未提供,则为 null。 |
CompletedTask |
获取一个已成功完成的任务。 |
CreationOptions |
获取用于创建此任务的 TaskCreationOptions。 |
CurrentId |
返回当前正在执行 Task 的 ID。 |
Exception |
获取导致 AggregateException 提前结束的 Task。 如果 Task 成功完成或尚未引发任何异常,这将返回 |
Factory |
提供对用于创建 Task 和 Task<TResult> 的工厂方法的访问。 |
Id |
获取此 Task 实例的 ID。 |
IsCanceled |
获取此 Task 实例是否由于被取消的原因而已完成执行。 |
IsCompleted |
获取此 Task 是否已完成。 |
IsFaulted |
获取 Task 是否由于未经处理异常的原因而完成。 |
Status |
获取此任务的 TaskStatus。 |
方法
显式界面实现
IAsyncResult.AsyncWaitHandle |
获取可用于等待任务完成的 WaitHandle。 |
IAsyncResult.CompletedSynchronously |
获取操作是否已同步完成的指示。 |
适用于
.NET Core
.NET Framework
.NET Standard
Xamarin.Android
Xamarin.iOS
Xamarin.Mac
线程安全性
所有成员Task,除Dispose()、 是线程安全的可从多个线程同时使用。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
2013-12-02 在ASP.NET应用程序中使用身份模拟(Impersonation)