你的位置:首页 > 软件开发 > ASP.net > 使用 Async 和 Await 的异步编程(C# 和 Visual Basic)[msdn.microsoft.com]

使用 Async 和 Await 的异步编程(C# 和 Visual Basic)[msdn.microsoft.com]

发布时间:2016-03-08 19:00:07
看到Microsoft官方一篇关于异步编程的文章,感觉挺好,不敢独享,分享给大家。原文地址:https://msdn.microsoft.com/zh-cn/library/hh191443.aspx通过使用异步编程,你可以避免性能瓶颈并增强应用程序的总体响应能力。 但是,编 ...

看到Microsoft官方一篇关于异步编程的文章,感觉挺好,不敢独享,分享给大家。

原文地址:https://msdn.microsoft.com/zh-cn/library/hh191443.aspx

通过使用异步编程,你可以避免性能瓶颈并增强应用程序的总体响应能力。 但是,编写异步应用程序的传统技术可能比较复杂,使它们难以编写、调试和维护。

Visual Studio 2012 引入了一个简化的方法(即异步编程),该方法利用 .NET Framework 4.5 和 Windows 运行时中的异步支持。 编译器可执行开发人员曾进行的高难度工作,且应用程序保留了一个类似于同步代码的逻辑结构。 因此,你只需做一小部分工作就可以获得异步编程的所有好处。

本主题概述了何时以及如何使用异步编程,并包括指向包含详细信息和示例的支持主题的链接。

异步对可能引起阻塞的活动(例如应用程序访问 Web 时)至关重要。 对 Web 资源的访问有时很慢或会延迟。 如果此类活动在同步过程中受阻,则整个应用程序必须等待。 在异步过程中,应用程序可继续执行不依赖 Web 资源的其他工作,直至潜在阻止任务完成。

下表显示了异步编程提高响应能力的典型应用场景。 从 .NET Framework 4.5 和 Windows 运行时中列出的 API 包含支持异步编程的方法。

应用程序区域

包含异步方法的受支持的 API

Web 访问

HttpClient SyndicationClient

使用文件

StorageFile、StreamWriter、StreamReader、

使用图像

MediaCapture、BitmapEncoder、BitmapDecoder

WCF 编程

同步和异步操作

  

Visual Basic 中的 Async 和 Await 关键字,以及 C# 中的 async 和 await 关键字都是异步编程的核心。 通过使用这两个关键字,你可以使用 .NET framework 或 Windows 运行时中的资源轻松创建异步方法(几乎与创建同步方法一样轻松)。 通过使用被称为异步方法的 async 和 await 定义的异步方法。

下面的示例演示了一种异步方法。 你应对代码中的几乎所有内容都非常熟悉。 注释调出你添加的用来创建异步的功能。

你可以在本主题的末尾找到完整的示例文件,并且可以从 Async 示例:“使用 Async 和 Await 进行异步编程”的示例下载此示例。

 1 // Three things to note in the signature: 2 // - The method has an async modifier.  3 // - The return type is Task or Task<T>. (See "Return Types" section.) 4 //  Here, it is Task<int> because the return statement returns an integer. 5 // - The method name ends in "Async." 6 async Task<int> AccessTheWebAsync() 7 {  8   // You need to add a reference to System.Net.Http to declare client. 9   HttpClient client = new HttpClient();10 11   // GetStringAsync returns a Task<get='_blank'>string>. That means that when you await the12   // task you'll get a string (urlContents).13   Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");14 15   // You can do work here that doesn't rely on the string from GetStringAsync.16   DoIndependentWork();17 18   // The await operator suspends AccessTheWebAsync.19   // - AccessTheWebAsync can't continue until getStringTask is complete.20   // - Meanwhile, control returns to the caller of AccessTheWebAsync.21   // - Control resumes here when getStringTask is complete. 22   // - The await operator then retrieves the string result from getStringTask.23   string urlContents = await getStringTask;24 25   // The return statement specifies an integer result.26   // Any methods that are awaiting AccessTheWebAsync retrieve the length value.27   return urlContents.Length;28 }

异步编程中最需弄清的是控制流是如何从方法移动到方法的。 下图可引导你完成该过程。

使用 Async 和 Await 的异步编程(C# 和 Visual Basic)[msdn.microsoft.com]

关系图中的数值对应于以下步骤。

  1. 事件处理程序调用并等待 AccessTheWebAsync 异步方法。

  2. AccessTheWebAsync 可创建 HttpClient 实例并调用 GetStringAsync 异步方法以下载网站内容作为字符串。

  3. GetStringAsync 中发生了某种情况,该情况挂起了它的进程。 可能必须等待网站下载或一些其他阻止活动。 为避免阻止资源,GetStringAsync 会将控制权出让给其调用方 AccessTheWebAsync。

    GetStringAsync 返回 Task<TResult>,其中 TResult 为字符串,并且 AccessTheWebAsync 将任务分配给 getStringTask 变量。 该任务表示调用 GetStringAsync 的正在进行的进程,其中承诺当工作完成时产生实际字符串值。

  4. 由于尚未等待 getStringTask,因此,AccessTheWebAsync 可以继续执行不依赖于 GetStringAsync 得出的最终结果的其他工作。 该任务由对同步方法 DoIndependentWork 的调用表示。

  5. DoIndependentWork 是完成其工作并返回其调用方的同步方法。

  6. AccessTheWebAsync 已用完工作,可以不受 getStringTask 的结果影响。 接下来,AccessTheWebAsync 需要计算并返回该下载字符串的长度,但该方法仅在具有字符串时才能计算该值。

    因此,AccessTheWebAsync 使用一个 await 运算符来挂起其进度,并把控制权交给调用 AccessTheWebAsync 的方法。AccessTheWebAsync 将 Task(Of Integer) 或 Task<int> 返回至调用方。 该任务表示对产生下载字符串长度的整数结果的一个承诺。

    使用 Async 和 Await 的异步编程(C# 和 Visual Basic)[msdn.microsoft.com]注意

    如果 GetStringAsync(因此 getStringTask)在 AccessTheWebAsync 等待前完成,则控件会保留在 AccessTheWebAsync 中。 如果异步调用过程 (AccessTheWebAsync) 已完成,并且 AccessTheWebSync 不必等待最终结果,则挂起然后返回到 getStringTask 将造成成本浪费。

    在调用方内部(此示例中的事件处理程序),处理模式将继续。 在等待结果前,调用方可以开展不依赖于 AccessTheWebAsync 结果的其他工作,否则就需等待片刻。 事件处理程序等待 AccessTheWebAsync,而 AccessTheWebAsync 等待 GetStringAsync

  7. GetStringAsync 完成并生成一个字符串结果。 字符串结果不是通过按你预期的方式调用 GetStringAsync 所返回的。 (记住,该方法已返回步骤 3 中的一个任务)。 相反,字符串结果存储在表示完成 getStringTask 方法的任务中。 await 运算符从 getStringTask 中检索结果。赋值语句将检索到的结果赋给 urlContents。

  8. 当 AccessTheWebAsync 具有字符串结果时,该方法可以计算字符串长度。 然后,AccessTheWebAsync 工作也将完成,并且等待事件处理程序可继续使用。 在此主题结尾处的完整示例中,可确认事件处理程序检索并打印长度结果的值。

如果你不熟悉异步编程,请花 1 分钟时间考虑同步行为和异步行为之间的差异。 当其工作完成时(第 5 步)会返回一个同步方法,但当其工作挂起时(第 3 步和第 6 步),异步方**返回一个任务值。 在异步方法最终完成其工作时,任务会标记为已完成,而结果(如果有)将存储在任务中。

有关控制流的更多信息,请参见 异步程序中的控制流(C# 和 Visual Basic)。

API 异步方法 

你可能想知道从何处可以找到 GetStringAsync 等支持异步编程的方法。.NET Framework 4.5 包含使用 async 和 await 的许多成员。 可以通过附加到成员名称的“Async”后缀和 Task 或 Task<TResult> 的返回类型识别这些成员。 例如,System.IO.Stream 类包含的方法CopyToAsync、ReadAsync、WriteAsync 等方法以及同步方法 CopyTo、Read 和 Write。

Windows 运行时还包含许多在 Windows 8.x 应用商店应用中可与 async 和 await 一起使用的方法。 有关更多信息和示例方法,请参见快速入门:将 await 运算符用于异步编程、异步编程(Windows 应用商店应用)和WhenAny:.NET Framework 和 Windows 运行时之间的桥接(C# 和 Visual Basic)。

异步方法旨在成为非阻止操作。 异步方法中的 await 表达式在等待的任务正在运行时不会阻止当前线程。 相反,表达式在继续时注册方法的其余部分并将控件返回到异步方法的调用方。

async 和 await 关键字不会导致创建其他线程。 因为异步方法不会在其自身线程上运行,因此它不需要多线程。 只有当方法处于活动状态时,该方法将在当前同步上下文中运行并使用线程上的时间。 可以使用 Task.Run 将占用大量 CPU 的工作移到后台线程,但是后台线程不会帮助正在等待结果的进程变为可用状态。

对于异步编程而言,该基于异步的方法优于几乎每个用例中的现有方法。 具体而言,此方法比 BackgroundWorker 更适用于 IO 绑定的操作,因为此代码更简单且无需防止争用条件。 结合 Task.Run 使用时,异步编程比 BackgroundWorker 更适用于 CPU 绑定的操作,因为异步编程将运行代码的协调细节与 Task.Run 传输至线程池的工作区分开来。

异步和等待 

如果通过使用 Async 或 async 修饰符指定某种方法为异步方法,则可以启用以下两个功能。

  • 标记的异步方法可以使用 Await 或 await 来指定悬挂点。 await 运算符通知编译器异步方法只有直到等待的异步过程完成才能继续通过该点。同时,控件返回至异步方法的调用方。

    await 表达式中异步方法的挂起不能使该方法退出,并且 finally 块不会运行。

  • 标记的异步方法本身可以通过调用它的方法等待。

异步方法通常包含 await 运算符的一个或多个匹配项,但缺少 await 表达式不会导致编译器错误。 如果异步方法未使用 await 运算符标记悬挂点,则该方法将作为同步方法执行,不管异步修饰符如何。 编译器将为此类方法发布一个警告。

AsyncasyncAwait 和 await 都是上下文关键字。 有关更多信息和示例,请参见以下主题:

  •  Async (Visual Basic)

  • async(C# 参考)

  • Await 运算符 (Visual Basic)

  • await(C# 参考)

在 .NET Framework 编程中,异步方法通常返回 Task 或 Task<TResult>。 在异步方法中,await 运算符应用于通过调用另一个异步方法返回的任务。

如果方法包含指定 TResult 类型的操作数的 Return (Visual Basic) 或 return (C#) 语句,则将 Task<TResult> 指定为返回类型。

如果方法不含任何 return 语句或包含不返回操作数的 return 语句,则将 Task 用作返回类型。

下面的示例演示如何声明并调用可返回 Task<TResult> 或 Task 的方法。

1 // Signature specifies Task<TResult> async Task<int> TaskOfTResult_MethodAsync() { int hours; // . . . // Return statement specifies an integer result. return hours; } // Calls to TaskOfTResult_MethodAsync Task<int> returnedTaskTResult = TaskOfTResult_MethodAsync(); int intResult = await returnedTaskTResult; // or, in a single statement int intResult = await TaskOfTResult_MethodAsync(); // Signature specifies Task async Task Task_MethodAsync() { // . . . // The method has no return statement. } // Calls to Task_MethodAsync Task returnedTask = Task_MethodAsync(); await returnedTask; // or, in a single statement await Task_MethodAsync();

按照约定,将“Async”追加到具有 Async 或 async 修饰符的方法的名称。

如果某一约定中的事件、基类或接口协定建议其他名称,则可以忽略此约定。 例如,你不应重命名常用事件处理程序,例如 Button1_Click。

下面的代码是来自于本主题讨论的 Windows Presentation Foundation (WPF) 应用程序的 MainWindow.xaml.vb 或 MainWindow.xaml.cs 文件。 可以从 异步示例:“使用 Async 和 Await 进行异步编程”的示例中下载示例。

 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Windows; 7 using System.Windows.Controls; 8 using System.Windows.Data; 9 using System.Windows.Documents;10 using System.Windows.Input;11 using System.Windows.Media;12 using System.Windows.Media.Imaging;13 using System.Windows.Navigation;14 using System.Windows.Shapes;15 16 // Add a using directive and a reference for System.Net.Http;17 using System.Net.Http;18 19 namespace AsyncFirstExample20 {21   public partial class MainWindow : Window22   {23     // Mark the event handler with async so you can use await in it.24     private async void StartButton_Click(object sender, RoutedEventArgs e)25     {26       // Call and await separately.27       //Task<int> getLengthTask = AccessTheWebAsync();28       //// You can do independent work here.29       //int contentLength = await getLengthTask;30 31       int contentLength = await AccessTheWebAsync();32 33       resultsTextBox.Text +=34         String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);35     }36 37 38     // Three things to note in the signature:39     // - The method has an async modifier. 40     // - The return type is Task or Task<T>. (See "Return Types" section.)41     //  Here, it is Task<int> because the return statement returns an integer.42     // - The method name ends in "Async."43     async Task<int> AccessTheWebAsync()44     { 45       // You need to add a reference to System.Net.Http to declare client.46       HttpClient client = new HttpClient();47 48       // GetStringAsync returns a Task<string>. That means that when you await the49       // task you'll get a string (urlContents).50       Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");51 52       // You can do work here that doesn't rely on the string from GetStringAsync.53       DoIndependentWork();54 55       // The await operator suspends AccessTheWebAsync.56       // - AccessTheWebAsync can't continue until getStringTask is complete.57       // - Meanwhile, control returns to the caller of AccessTheWebAsync.58       // - Control resumes here when getStringTask is complete. 59       // - The await operator then retrieves the string result from getStringTask.60       string urlContents = await getStringTask;61 62       // The return statement specifies an integer result.63       // Any methods that are awaiting AccessTheWebAsync retrieve the length value.64       return urlContents.Length;65     }66 67 68     void DoIndependentWork()69     {70       resultsTextBox.Text += "Working . . . . . . .\r\n";71     }72   }73 }74 75 // Sample Output:76 77 // Working . . . . . . .78 79 // Length of the downloaded string: 41564.

async(C# 参考)

原标题:使用 Async 和 Await 的异步编程(C# 和 Visual Basic)[msdn.microsoft.com]

关键词:C#

C#
*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

可能感兴趣文章

我的浏览记录