使用 Async 和 Await 的异步编程(C# 和 Visual Basic)

来源:岁月联盟 编辑:exp 时间:2012-11-09

为什么使用Asynchrony?
使用异步编程时,可以在可能需要长时间运行的代码指定点处理挂起,当程序的其他部分无法继续时。 此技术来避免可能的性能瓶颈并增强应用程序的总体响应能力。 Asynchrony到可能会阻塞事件很重要,例如,当程序访问该web。 如果该事件在块同步过程,整个程序块。 在异步,则当阻塞任务完成其工作时,进程,程序可以取得进展在其他方面。
因为所有与用户界面相关的事件通常共享一个线程,Asynchrony尤其重要的进程访问UI线程。 如果任何处理块,所有块。
对于块的示例中通过“测试同步解决方案”节处理,按照 演练:使用 Async 和 Await 访问 Web(C# 和 Visual Basic) 的步骤。 或者,您可以下载演练中的代码从 Async示例:访问Web演练 并运行名为SyncWalkthrough的项目。 当用户界面线程同步下载从web中的内容,无法移动控件或调整窗口的大小。 如果您不希望等待,不能即使关闭它关闭程序。
使用异步和请等待创建异步解决方案
Async (Visual Basic)或 async (C#)修饰符和 等待 (Visual Basic)或 等待 (C#)运算符对异步编程是基本的。 async修饰符指示编译器方法或lambda表达式是异步的,并且可以使用请等待运算符指定在方法中悬挂点。 这种方法引用异步方法。
在异步方法中,您可以等待运算符应用于特定任务挂起异步方法的执行,直到等待的任务完成。 同时,控件返回到异步方法的调用方。 保存并不构成从异步方法的退出,并且,finally 块不会运行。
编译器实现用于开发人员执行,包括注册挂起的方法中完成的延续的困难工作。 因此,异步代码容易编写,并且,如果您的程序保留类似于同步代码的逻辑结构。 例如,某些实例处理,例如循环,而异常处理,可能很难进行在传统异步代码编写。 在异步方法,解决您编写这些元素,因为在一个同步解决方案会并将问题。 有关asynchrony以前的方法的更多信息在.NET Framework,请参见 TPL 和传统 .NET 异步编程。
.NET Framework 4.5 包含与异步以及等待的许多成员。 您可以通过附加到成员名称和 Task 或 Task<TResult>的返回类型“Async”后缀识别这些成员。 例如,System.IO.Stream选件类包含方法例如 CopyToAsync、ReadAsync和 WriteAsync 在同步方法 CopyTo、Read和 Write。
示例
下面的示例通过比较同步编写与方法相同的方法声明此方法很简单,如果已编写以异步方式。 有关完整的示例,请参见演练:使用 Async 和 Await 访问 Web(C# 和 Visual Basic)。
下面的更改将同步方法(GetURLContents)转换为异步方法(GetURLContentsAsync)。
以下方式更改方法签名。
标记与 Async 或 async 修饰符的方法。
更改返回类型从 Byte() 到在Visual Basic中 Task(Of Byte()) 或从 byte[] 到 Task<byte[]> 在C#。
在异步操作完成时,任务是承诺提供的字节数组。 有关异步的更多信息返回类型,请参见 异步返回类型(C# 和 Visual Basic)。
按照约定,添加后缀“Async”到方法的名称。
在方法体,请进行以下更改。
替换调用长时间运行的同步方法通过调用相应的异步方法。 在此示例中,将替换调用 GetResponse 在调用 GetResponseAsync。
应用 Await 或方法的结果的 await 运算符调用。
替换调用 CopyTo 在调用 CopyToAsync。
应用 Await 或方法的结果的 await 运算符调用。
转换完成。 有关完整的示例和分步说明,请参见 演练:使用 Async 和 Await 访问 Web(C# 和 Visual Basic)。
C#
VB
复制
                    // Synchronous version of a method that downloads the resource that a URL
                    // links to and then returns its content.
                    private
                    byte[] GetURLContents(string url)
{
    // The downloaded resource ends up in the variable named content.var content = new MemoryStream();

    // Initialize an HttpWebRequest for the current URL.var webReq = (HttpWebRequest)WebRequest.Create(url);

    // Send the request to the Internet resource, and wait for// the response.using (var response = webReq.GetResponse())
    {
        // Get the data stream that is associated with the specified URL.using (Stream responseStream = response.GetResponseStream())
        {
            // Read the bytes in responseStream, and copy them to content. 
            responseStream.CopyTo(content);
        }
    }

    // Return the result as a byte array.return content.ToArray();
}


// Asynchronous version of the same method. The changed lines //are marked with **.// **Add the async modifier. Change the method name and the return type.privateasync Task<byte[]> GetURLContentsAsync(string url)
{
    // The downloaded resource ends up in the variable named content.var content = new MemoryStream();

    // Initialize an HttpWebRequest for the current URL.var webReq = (HttpWebRequest)WebRequest.Create(url);

    // **Call GetResponseAsync instead of GetResponse, and await the result.// GetResponseAsync returns a Task<WebResponse>.using (WebResponse response = await webReq.GetResponseAsync())
    {
        // Get the data stream that is associated with the specified URL.using (Stream responseStream = response.GetResponseStream())
        {
            // ** Call CopyToAsync instead of CopyTo, and await the response.// CopyToAsync returns a Task, not a Task<T>.await responseStream.CopyToAsync(content);
        }
    }
    // Return the result as a byte array.return content.ToArray();
}

异步和等待关键字
Async 或 async 修饰符修改异步方法。 方法通常包含 Await 或 await 运算符的一个或多个匹配项,但是,请假等待表达式不会导致编译器错误。 如果异步方法不会将等待运算符指示悬挂点,则尽管"修饰符执行,一个同步方法。 编译器会发出此类方法的警告。
Async 、async、Await和 await 是上下文关键字。 有关更多信息和示例,请参见以下主题:
Async (Visual Basic)
async(C# 参考)
Await 运算符 (Visual Basic)
await(C# 参考)
返回类型和参数
在Visual Basic中,异步方法是 sub 程序或具有 Task 或 Task<TResult>的一个返回类型的 功能 程序。
在C#,异步方法可以具有 无效、Task或 Task<TResult>的返回类型。
若要使异步方法的调用方等待计算完成,请使用 Task 或 Task<TResult>的一个返回类型。 您指定 Task<TResult>,因为返回类型,则方法包含指定类型 TResult操作数的一个 返回 (Visual Basic)或 返回 (C#)语句。 使用 Task,如果方法没有返回语句或具有不返回操作数的return语句。
Sub 方法(Visual Basic)或 void 返回类型(C#)主要用于定义事件处理程序,void 返回类型需要。 是 Sub 程序或具有 void 返回类型不能等待的异步方法和一个无效返回的方法的调用方无法捕获方法引发的任何异常。
异步方法不能声明在 Visual Basic 或 ByRef parameters in Visual Basic or ref or out 参数或参数在 C#,但是,方法可以调用具有这些参数的方法。
有关更多信息和示例,请参见异步返回类型(C# 和 Visual Basic)。 有关如何捕获异步方法的异常的更多信息,请参见 try-catch(C# 参考) 或 Try...Catch...Finally 语句 (Visual Basic)。
命名约定
按照约定,添加后缀“Async”在一个 Async 或 async 修饰符方法的名称。
您可以忽略事件、基类或接口协定建议一个不同的名称约定。 例如,您不应向常用事件处理程序重命名,例如 button1_Click。
线程
异步方法旨在成为非阻塞操作。 当等待的任务运行时,在异步方法的一个等待表达式不会阻止当前线程。 相反,该表达式注册该方法的其余部分作为继续并返回控制对异步方法的调用方。
因为异步方法本身并不会运行的线程,异步方法不需要多线程。 只有在方法处于活动状态,则方法在当前同步上下文中运行并使用在线程的时间。 有关如何移动异步方法或lambda表达式的信息移到后台线程,请参见 Task.Run。