文章内容
2017/11/5 17:18:01,作 者: 黄兵
await(C# 参考)
await
运算符应用于异步方法中的任务,在方法的执行中插入挂起点,直到所等待的任务完成。 任务表示正在进行的工作。
await
仅可用于由 async 关键字修改的异步方法中。 使用 async
修饰符定义并且通常包含一个或多个 await
表达式的这类方法称为异步方法。
备注
async
和 await
关键字是在 C# 5 中引入的。 有关异步编程的说明,请参阅使用 Async 和 Await 的异步编程。
应用 await
运算符的任务通常由实现基于任务的异步模式的方法调用返回。 包括返回 Task、Task<TResult> 和 System.Threading.Tasks.ValueType<TResult>
对象的方法。
如下示例中,HttpClient.GetByteArrayAsync 方法返回 Task<byte[]>
。 当任务完成时,任务约定生成实际字节数组。 await
运算符挂起执行,直到 GetByteArrayAsync 方法完成其操作。 同时,控制权会返回给 GetPageSizeAsync
的调用方。 任务结束执行时,await
表达式的计算结果为字节数组。
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
string[] args = Environment.GetCommandLineArgs();
if (args.Length > 1)
GetPageSizeAsync(args[1]).Wait();
else
Console.WriteLine("Enter at least one URL on the command line.");
}
private static async Task GetPageSizeAsync(string url)
{
var client = new HttpClient();
var uri = new Uri(Uri.EscapeUriString(url));
byte[] urlContents = await client.GetByteArrayAsync(uri);
Console.WriteLine($"{url}: {urlContents.Length/2:N0} characters");
}
}
// The following call from the command line:
// await1 http://docs.microsoft.com
// displays output like the following:
// http://docs.microsoft.com: 7,967 characters
重要
有关完整示例,请参阅演练:使用 async 和 await 访问 Web。 可以从 Microsoft 网站的开发者代码示例中下载示例。 该示例处于 AsyncWalkthrough_HttpClient 项目中。
如前一示例所示,如果 await
应用于返回 Task<TResult>
的方法调用的结果,则 await
表达式的类型为 TResult
。 如果 await
应用于返回 Task
的方法调用的结果,则 await
表达式的类型为 void
。 以下示例演示了差异。
// await keyword used with a method that returns a Task<TResult>.
TResult result = await AsyncMethodThatReturnsTaskTResult();
// await keyword used with a method that returns a Task.
await AsyncMethodThatReturnsTask();
// await keyword used with a method that returns a ValueTask<TResult>.
TResult result = await AsyncMethodThatReturnsValueTaskTResult();
await
表达式不阻止正在执行它的线程。 而是使编译器将剩下的异步方法注册为等待任务的延续任务。 控制权随后会返回给异步方法的调用方。 任务完成时,它会调用其延续任务,异步方法的执行会在暂停的位置处恢复。
await
表达式只能在由 async
修饰符标记的封闭方法体、lambda 表达式或异步方法中出现。 术语 await 在该上下文中仅用作关键字。 在其他位置,它会解释为标识符。 在方法、Lambda 表达式或匿名方法中,await
表达式不能在同步函数体、查询表达式、lock 语句块或不安全上下文中出现。
异常
大多数异步方法返回 Task 或 Task<TResult>。 返回任务的属性携带有关其状态和历史记录的信息,如任务是否完成、异步方法是否导致异常或已取消以及最终结果是什么。 await
运算符通过在由 GetAwaiter
方法返回的对象上调用方法来访问那些属性。
如果等待的返回任务的异步方法会导致异常,则 await
运算符重新引发异常。
如果等待的任务返回异步方法取消,则 await
运算符会重新引发 OperationCanceledException。
处于故障状态的单个任务可以反映多个异常。 例如,任务可能是对 Task.WhenAll 调用的结果。 等待此类任务时,等待操作仅重新引发异常之一。 但是,无法预测重新引发的异常。
有关异步方法中的错误处理的示例,请参阅 try catch。
示例
下面的示例返回页面(页面 URL 作为命令行参数传递给页面)中的字符总数。 此示例调用 GetPageLengthsAsync
方法,此方法标记有 async
关键字。 而 GetPageLengthsAsync
方法使用 await
关键字等待对 HttpClient.GetStringAsync 方法的调用。
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
class Example
{
static void Main()
{
string[] args = Environment.GetCommandLineArgs();
if (args.Length < 2)
throw new ArgumentNullException("No URLs specified on the command line.");
long characters = GetPageLengthsAsync(args).Result;
Console.WriteLine($"{args.Length - 1} pages, {characters:N0} characters");
}
private static async Task<long> GetPageLengthsAsync(string[] args)
{
var client = new HttpClient();
long pageLengths = 0;
for (int ctr = 1; ctr < args.Length; ctr++) {
var uri = new Uri(Uri.EscapeUriString(args[ctr]));
string pageContents = await client.GetStringAsync(uri);
Interlocked.Add(ref pageLengths, pageContents.Length);
}
return pageLengths;
}
}
由于不支持在应用程序入口点中使用 async
和await
,因此我们无法将 async
属性应用到 Main
方法,也无法等待 GetPageLengthsAsync
方法调用。 我们可通过检索 Task<TResult>.Result 属性的值来确保 Main
方法等待异步操作完成。 对于不返回值的任务,可调用 Task.Wait 方法。
本文转载自:await(C# 参考)
评论列表