Task
类是.NET 4.0
之后提供的异步操作抽象,完整路径为System.Threading.Tasks.Task
。
Task
类用于表示无返回值的异步操作,对于带有返回值的异步操作应使用Task
类的子类Task<TResult>
。 Task
类创建的任务会加入线程池中。
Task/Task<TResult>
类的主要构造函数如下:
// 接收Action类型作为异步操作的执行内容
public Task(Action action);
// 首参数为带有一个参数的Action<Object>类型,第二参数为要传入的内容
public Task(Action<object> action, object state);
// TaskCreationOptions类型为枚举,并设定TaskScheduler的执行策略
public Task(Action action, TaskCreationOptions creationOptions);
// 在Task<TResult>类中接收Func<TResult>类型作为异步执行的内容
public Task(Func<TResult> function);
public Task(Func<object, TResult> function, object state);
创建完毕的Task
可以使用Start()
方法开始执行:
// 将任务添加到当前的TaskScheduler(任务调度器)中,任务调度器选择合适的时机执行
public void Start();
// 将任务添加到特定的TaskScheduler中
public void Start(TaskScheduler scheduler);
在实际开发中,更多情况下使用Task
类的静态方法Run()
或者工厂类TaskFactory
的成员方法StartNew()
来创建和启动新的任务。
Task
类中的一些常用方法:
// 将参数中的异步操作在当前调度器中排队,并返回Task对象
public static Task Run(Action action);
public static Task<TResult> Run<TResult>(Func<TResult> function);
// 等待Task完成
public void Wait(); //等待当前任务完成
public static void WaitAll(params Task[] tasks); //等待任务数组中的所有任务完成
public static bool WaitAll(Task[] tasks, int millisecondsTimeout;) //等待指定时间
C# 5.0
之后引入了async
和await
关键字,在语言层面给予了并发更好的支持。
async
用于标记异步方法: async
关键字是上下文关键字,只有在修饰方法与Lambda时才会被当作关键字处理,在其它区域将被作为标识符处理。async
关键字可以标记静态方法,但不能标记入口点(Main()
方法)。async
标记的方法返回值必须为Task
、Task<TResult>
、void
其中之一。await
用于等待异步方法的结果: await
关键字同样是上下文关键字,只有在async
标记的方法中才被视为关键字。await
关键字可以用在async
方法和Task
、Task<TResult>
之前,用于等待异步任务执行结束。一个简单的async
方法结构如下:
async Task testAsync()
{
... //顺序执行的内容
return await Task.Run(() =>
{
... //异步执行的内容
});
}
并不是方法使用async
关键字标记了就是异步方法,直接出现在async
方法内部的语句也是同步执行的,异步执行的内容需要使用Task
类执行。
事实上,一个不包含任何await
语句的async
方法将是同步执行的,此时编译器会给出警告。
简单示例,使用async/await
在屏幕并发输出内容:
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
// Task.Run()方法中的Function是真正异步执行的内容
static async Task<int> Async()
=> await Task.Run<int>(() =>
{
// 线程ID与Handler()方法不同
Console.WriteLine("Async() Thread ID: [{0}]", Thread.CurrentThread.ManagedThreadId);
for (int i = 0; i < 5; i++)
{
Thread.Sleep(100);
Console.WriteLine("Async: Run{0}", i);
}
Console.WriteLine("Over");
return 666;
});
// 返回值为void的async方法AsyncHandler()仅仅是包装器
static async void AsyncHandler()
{
// 方法体中的内容实际为同步执行,与Main()函数线程ID相同
Console.WriteLine("Handler() Thread ID: [{0}]", Thread.CurrentThread.ManagedThreadId);
// 调用异步方法Async()不会阻塞,Async()方法开始异步执行
Task<int> task = Async();
// 每隔0.1s打印输出,此时异步方法Async()也在另一线程中执行,同步打印输出
for (int i = 0; i < 3; i++)
{
Thread.Sleep(100);
Console.WriteLine("Handler: Run{0}", i);
}
// 在使用await之前的代码都运行在与Main()函数相同的线程
Console.WriteLine("Handler1() Thread ID: [{0}]", Thread.CurrentThread.ManagedThreadId);
// AsyncHandler()中的循环执行3次,此时异步方法Async()尚未执行完毕,使用await关键字会阻塞函数
// 在Main()函数中,从调用await开始,AsyncHandler()就已返回了
Console.WriteLine(await task);
// 使用await之后的代码运行在Async()方法所处的线程
Console.WriteLine("Handler2() Thread ID: [{0}]", Thread.CurrentThread.ManagedThreadId);
// 打印AsyncHandler()函数真正执行完毕信息
Console.WriteLine("Handler Really Finished!");
}
// Main方法不能标记为异步
static void Main(string[] args)
{
Console.WriteLine("Main() Thread ID: [{0}]", Thread.CurrentThread.ManagedThreadId);
AsyncHandler();
// 打印AsyncHandler()函数在Main()中已经执行完毕的信息
Console.WriteLine("Handler Finished in Main!");
// AsyncHandler()在实际执行完成之前就返回了,需要阻塞主线程等待AsyncHandler()真正执行完毕
Console.ReadLine();
}
}
输出结果:(Mono 4.4.0 && ArchLinux x64)
Main() Thread ID: [1]
Handler() Thread ID: [1]
Async() Thread ID: [4]
Handler: Run0
Async: Run0
Handler: Run1
Async: Run1
Async: Run2
Handler: Run2
Handler1() Thread ID: [1]
Handler Finished in Main!
Async: Run3
Async: Run4
Over
666
Handler2() Thread ID: [4]
Handler Really Finished!
由上述程序中不难看出,在async
关键字标记的异步方法中,使用await
之前的代码都是同步执行的,在调用了await
之后,剩余的代码便异步运行在独立的线程
原文: https://blog.csdn.net/u011152627/article/details/52044015