Task类与async/await

Task 类

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;)      //等待指定时间

async/await 关键字

C# 5.0之后引入了asyncawait关键字,在语言层面给予了并发更好的支持。

  1. async用于标记异步方法: 
    • async关键字是上下文关键字,只有在修饰方法与Lambda时才会被当作关键字处理,在其它区域将被作为标识符处理。
    • async关键字可以标记静态方法,但不能标记入口点(Main()方法)。
    • async标记的方法返回值必须为TaskTask<TResult>void其中之一。
  2. await用于等待异步方法的结果: 
    • await关键字同样是上下文关键字,只有在async标记的方法中才被视为关键字。
    • await关键字可以用在async方法和TaskTask<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;
            });

    // 返回值为voidasync方法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

猜你喜欢

转载自blog.csdn.net/yuhan61659/article/details/81028065
今日推荐