C# 中的异步和等待关键字

在异步编程中,C#提供了两个关键字:async和await。使用这两个关键字可以实现异步操作,使得程序在等待数据返回时不会暂停,而是可以去执行其它任务。本文将详细介绍C#中的异步和等待关键字。

1. 异步编程

异步编程可以加速应用程序的运行。举个例子来说,如果需要下载一个大文件,如果使用同步方式的话,程序会停在那里,直到下载完毕才继续运行下面的代码。但如果使用异步方式,程序不会停止运行,而是可以继续执行其它任务。等到下载完成后再回调这个任务。

1.1 async关键字

async关键字声明一个方法是异步方法。使用async关键字可以告诉编译器,这个方法将会异步执行,而非同步执行。

async Task<int> GetPageLengthAsync()

{

HttpClient client = new HttpClient();

var html = await client.GetStringAsync("http://www.baidu.com");

return html.Length;

}

使用async关键字声明一个异步方法

上面的代码中,GetPageLengthAsync()方法用了async关键字,返回类型为Task<int>。使用async关键字后,可以使用await关键字等待异步操作的完成。

1.2 await关键字

await关键字是用来等待异步操作的返回结果的。使用await关键字可以让程序在等待数据返回时不会暂停,而是可以去执行其它任务。等到异步操作返回结果后再继续执行下面的代码。

HttpClient client = new HttpClient();

var html = await client.GetStringAsync("http://www.baidu.com");

使用await关键字等待异步操作的完成

在上面的代码中,await关键字等待异步操作GetStringAsync()返回结果后继续执行。

1.3 Task和Task<T>

在异步编程中,Task是一个重要的类型。使用Task可以轻松实现异步操作。Task<T>表示一个异步操作结果的包装器。

Task<int> task = GetPageLengthAsync();

使用Task<T>包装异步操作的结果

上面的代码中,GetPageLengthAsync()方法返回的类型是Task<int>。使用这个Task<int>可以获得异步操作的结果。

2. 等待关键字

等待关键字是用于等待异步操作完成的关键字,等待关键字有多种类型,下面将一一介绍。

2.1 Task.Wait

Task.Wait表示当前线程等待异步操作的完成。Wait会一直等到异步操作完成为止。

Task task = Task.Run(() =>

{

for(int i = 0; i < 5; i++)

{

Console.WriteLine("working...");

Thread.Sleep(1000);

}

});

task.Wait();

Console.WriteLine("task completed.");

使用Task.Wait等待异步操作的完成

上面的代码中,task.Wait()等待异步操作task的完成,直到任务完成后才输出"task completed."。

2.2 Task.Delay

Task.Delay可以使当前线程等待指定的时间之后再继续运行。Delay返回的是一个Task,可以使用await关键字等待Delay的完成。

async void Wait()

{

Console.WriteLine("start waiting...");

await Task.Delay(3000);

Console.WriteLine("end waiting...");

}

Wait();

使用Task.Delay实现等待

上面的代码中,Wait()方法使用了async关键字和await关键字来等待Task.Delay的完成,等待3秒之后再输出"end waiting..."。

2.3 Task.WhenAny

Task.WhenAny可以使当前线程等待多个异步操作中的任意一个完成之后再继续运行。WhenAny返回的是一个Task,可以使用await关键字等待WhenAny的完成。当其中任意一个异步操作完成时,Task将返回这个异步操作的Task。

async void WaitAny()

{

Console.WriteLine("start wait any...");

Task<int> t1 = Task.Run(() => { Thread.Sleep(1000); return 1; });

Task<string> t2 = Task.Run(() => { Thread.Sleep(2000); return "completed"; });

Task<Task<int>> TaskAny = Task.WhenAny(t1, t2);

Task<int> result = await TaskAny;

Console.WriteLine("result: " + result.Result);

}

WaitAny();

使用Task.WhenAny实现等待任意一个异步任务完成

上面的代码中,WaitAny()方法用了async关键字和await关键字来等待Task.WhenAny的完成。当t1和t2中有任意一个完成时,Task将返回这个异步操作的Task。

2.4 Task.WhenAll

Task.WhenAll可以使当前线程等待多个异步操作全部完成之后再继续运行。WhenAll返回的是一个Task,可以使用await关键字等待WhenAll的完成。当所有的异步操作完成时,Task将返回所有异步操作结果的Task数组。

async void WaitAll()

{

Console.WriteLine("start wait all...");

Task<int> t1 = Task.Run(() => { Thread.Sleep(1000); return 1; });

Task<int> t2 = Task.Run(() => { Thread.Sleep(2000); return 2; });

Task<int> t3 = Task.Run(() => { Thread.Sleep(3000); return 3; });

Task<int[]> TaskAll = Task.WhenAll(t1, t2, t3);

var results = await TaskAll;

Console.WriteLine("result: " + string.Join(",", results));

}

WaitAll();

使用Task.WhenAll实现等待多个异步任务全部完成

上面的代码中,WaitAll()方法用了async关键字和await关键字来等待Task.WhenAll的完成。当t1、t2和t3全部完成时,Task将返回所有异步操作结果的Task数组。

3. 总结

在C#中,异步和等待关键字可以使程序获得更高的效率。异步编程可以将任务分配给多个线程,从而加速应用程序的运行。而等待关键字可以控制异步操作的执行,保证异步操作完成之后再继续执行下面的代码。掌握异步和等待关键字对于C#程序员来说是非常重要的。

后端开发标签