C#语言基础之异步编程

背景:
编写异步应用程序的传统技术比较复杂,VS2012引入了简化方法,即使用Async和Await的异步编程,得到.NET Framework4.5和Windows运行时的异步支持。
何时进行异步编程(异步提高响应能力):
异步对可能引起阻塞的活动(应用程序访问Web资源)大有裨益。对Web资源的访问有时会很慢或延迟,如果此类活动发生在同步过程中,则整个应用程序必须得等待,在异步过程中,应用程序可以继续执行其他不依赖Web的资源。
下表显示了异步编程提高响应能力的典型应用场景。 从 .NET Framework 4.5 和 Windows 运行时中列出的 API 包含支持异步编程的方法。

应用程序区域 包含异步方法的受支持的API
Web访问 HttpClient,SyndicationClient
使用文件 StorageFile, StreamWriter, StreamReader, XmlReader
使用图像 MediaCapture, BitmapEncoder, BitmapDecoder
WCF编程 同步和异步操作

由于所有与用户界面相关的活动通常共享一个线程,因此,异步对访问 UI 线程的应用程序来说尤为重要。 如果在一个同步应用程序中有任何的线程被阻塞了,那么所有线程都将被阻塞。 你的应用程序停止响应,因此,你可能在其等待过程中认为它已经失败。
使用异步方法时,应用程序将继续响应 UI。 例如,你可以调整窗口的大小或最小化窗口;如果你不希望等待应用程序结束,则可以将其关闭。
更容易编写异步方法:
C# 中的 async 和 await 关键字都是异步编程的核心。 通过使用这两个关键字,你可以使用 .NET framework 或 Windows 运行时中的资源轻松创建异步方法(几乎与创建同步方法一样轻松)。
//异步方法签名中需要注意的三点:
//有一个async方法修饰符,如果没有该修饰符,编译器会将该方法等同于同步方法一样对待,不会报错
//返回类型为Task或者Task< TResult >
//约定方法名称以Async为后缀

Using System.Net.Http;
async Task< int > AccessTheWebAsync()
{ 
    //添加引用System.Net.Http 声明client.
    HttpClient client = new HttpClient();

    // GetStringAsync异步方法返回Task<string>. That means that when you await the 
    // task you'll get a string (urlContents).
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

    // You can do work here that doesn't rely on the string from GetStringAsync.
    DoIndependentWork();

    // The await operator suspends AccessTheWebAsync. 
    // - AccessTheWebAsync can't continue until getStringTask is complete. 
    // - Meanwhile, control returns to the caller of AccessTheWebAsync. 
    // - Control resumes here when getStringTask is complete. 
    // - The await operator then retrieves the string result from getStringTask. 
    string urlContents = await getStringTask;

    // The return statement specifies an integer result. 
    // Any methods that are awaiting AccessTheWebAsync retrieve the length value. 
    return urlContents.Length;
}

void DoIndependentWork()
{
   Console.WriteLine("Working ....");
}

如果要求AccessTheWebAsync在调用GetStringAsync和等待其完成任务期间不能进行其他工作,则可以使用下面单个语句中调用和等待来简化代码。

string urlContents=await client.GetStringAsync();

以下特征总结了使上一个示例成为异步方法的原因
1. 方法签名包含一个 Async(VB) 或 async (C#)修饰符。
2. 按照约定,异步方法的名称以“Async”后缀为结尾。
3. 返回类型为下列类型之一:
如果你的方法有操作数为 TResult 类型的返回语句,则为 Task< TResult >。
如果你的方法没有返回语句或具有没有操作数的返回语句,则为Task。
如果你编写的是异步事件处理程序,则为 Void(Visual Basic 中为 Sub)。
4. 方法通常包含至少一个 await 表达式,该表达式标记一个点,在该点上,直到等待的异步操作完成方法才能继续。 同时,将方法挂起,并且控制权返回到方法的调用方。
异步方法中发生的事情:
异步编程中最需要弄清楚的是控制流是如何从一个方法移动到另一个方法的
C#语言基础之异步编程_第1张图片
关系图中的数值对应于以下步骤。
1. 事件处理程序调用并等待 AccessTheWebAsync 异步方法。
2. AccessTheWebAsync 可创建 HttpClient 实例并调用 GetStringAsync 异步方法以下载网站内容作为字符串。
3. GetStringAsync 中发生了某种情况,该情况挂起了它的进程。 可能必须等待网站下载或一些其他阻止活动。 为避免阻止资源,GetStringAsync 会将控制权出让给其调用方 AccessTheWebAsync。
GetStringAsync 返回 Task,其中 TResult 为字符串,并且 AccessTheWebAsync 将任务分配给 getStringTask 变量。 该任务表示调用 GetStringAsync 的正在进行的进程,其中承诺当工作完成时产生实际字符串值。
4.由于尚未等待 getStringTask,因此,AccessTheWebAsync 可以继续执行不依赖于 GetStringAsync 得出的最终结果的其他工作。 该任务由对同步方法 DoIndependentWork 的调用表示。
5.DoIndependentWork 是完成其工作并返回其调用方的同步方法。
6.AccessTheWebAsync 已用完工作,可以不受 getStringTask 的结果影响。 接下来,AccessTheWebAsync 需要计算并返回该下载字符串的长度,但该方法仅在具有字符串时才能计算该值。
因此,AccessTheWebAsync 使用一个 await 运算符来挂起其进度,并把控制权交给调用 AccessTheWebAsync 的方法。 AccessTheWebAsync 将 Task(Of Integer) 或 Task< int > 返回至调用方。 该任务表示对产生下载字符串长度的整数结果的一个承诺。
如果 GetStringAsync(因此 getStringTask)在 AccessTheWebAsync 等待前完成,则控件会保留在 AccessTheWebAsync 中。 如果异步调用过程 (getStringTask) 已完成,并且 AccessTheWebSync 不必等待最终结果,则挂起然后返回到 AccessTheWebAsync 将造成成本浪费。
在调用方内部(此示例中的事件处理程序),处理模式将继续。 在等待结果前,调用方可以开展不依赖于 AccessTheWebAsync 结果的其他工作,否则就需等待片刻。事件处理程序等待 AccessTheWebAsync,而 AccessTheWebAsync 等待 GetStringAsync。
7.GetStringAsync 完成并生成一个字符串结果。 字符串结果不是通过按你预期的方式调用 GetStringAsync 所返回的。(请记住,此方法已在步骤 3 中返回一个任务。)相反,字符串结果存储在表示完成方法 getStringTask 的任务中。 await 运算符从 getStringTask 中检索结果。 赋值语句将检索到的结果赋给 urlContents。
8.当 AccessTheWebAsync 具有字符串结果时,该方法可以计算字符串长度。 然后,AccessTheWebAsync 工作也将完成,并且等待事件处理程序可继续使用。 在此主题结尾处的完整示例中,可确认事件处理程序检索并打印长度结果的值。
如果你不熟悉异步编程,请花 1 分钟时间考虑同步行为和异步行为之间的差异。 当其工作完成时(第 5 步)会返回一个同步方法,但当其工作挂起时(第 3 步和第 6 步),异步方法会返回一个任务值。 在异步方法最终完成其工作时,任务会标记为已完成,而结果(如果有)将存储在任务中。

你可能感兴趣的:(.net,异步,语言)