1. 程式人生 > >使用 Async 和 Await 的非同步程式設計

使用 Async 和 Await 的非同步程式設計

string urlContents = await client.GetStringAsync();

以下特徵總結了使上面一個非同步方法。
  • 方法簽名包含一個 Asyncasync 修飾符。

  • 非同步方法的名稱以“Async”字尾,按照約定,關閉。

  • 返回型別為下列型別之一:

    • ,如果您的方法具有操作個執行緒型別 TResult 的返回語句。

    • Task,如果方法沒有返回語句或具有返回語句不操作。

    • 無效 (在 Visual Basic 中 ),如果您編寫一個非同步事件處理程式。

  • 方法通常包含至少一個等待表示式,指示個方法無法繼續,直到該等待的非同步操作完成的。同時,方法被掛起,並且,控制元件返回到方法的呼叫方。

    本主題的下一節將解釋發生的懸掛點。

       在非同步方法,可以使用提供的關鍵字和型別指示要執行,因此,編譯器執行方式,包括記錄必須出現,當控制元件處於掛起的方法時回時間點。某些例項處理,例如迴圈,而異常處理,可能很難進行在傳統非同步程式碼的控制代碼。在非同步方法,解決您編寫這些元素,因為在一個同步解決方案會並將問題。

           若要了解的最重要的操作在非同步程式設計是控制流如何從方法移動到方法。下圖通過處理導致生成。

           

在關係圖的數值對應於以下步驟。

說明:
  1. 事件處理程式呼叫並等待 AccessTheWebAsync 非同步方法。

  2. AccessTheWebAsync

    建立 例項並呼叫 非同步方法下載網站內容作為字串。

  3. 掛起團隊進度的內容發生 GetStringAsync 發生。 可能必須等待網站下載或一些其他塊的事件。若要避免妨礙資源,GetStringAsync 為控制元件對其呼叫方,AccessTheWebAsync

    GetStringAsync返回 TResult 是字串的,並且,AccessTheWebAsync 將任務指派給getStringTask 變數。在工作完成時,任務表示繼續對定向到GetStringAsync,以提交導致實際字串值。

  4. 由於 getStringTask 不等待,AccessTheWebAsync 可以繼續執行不依賴於從 GetStringAsync

    的最終結果的其他工作。 該任務由為同步方法DoIndependentWork的呼叫表示。

  5. DoIndependentWork 完成其工作並回呼叫方的同步方法。

  6. AccessTheWebAsync 用完了它可以完成,不會受到getStringTask的結果的工作。接下來AccessTheWebAsync 若要計算並返回該下載的字串的長度,但是,該方法無法計算該值,直到該方法具有字串。

    因此,AccessTheWebAsync 使用一個等待運算子掛起的進度並使控制元件到呼叫AccessTheWebAsync的方法。AccessTheWebAsync 返回Task(Of Integer)Task<int> 呼叫方。任務表示形式導致為下載的字串的長度的整數結果。(說明:如果GetStringAsync (並 getStringTask) 後,在AccessTheWebAsync 等待之前,控制元件在AccessTheWebAsync保持。成本掛起然後返回到AccessTheWebAsync 將浪費,如果非同步呼叫過程 (getStringTask) 已經完成了,並且 AccessTheWebSync 不必等待最終結果。    在呼叫方 (在此示例中的事件處理程式內),處理重複。呼叫方可能完成不依賴於從AccessTheWebAsync 的結果在等待該結果之前的其他工作,或呼叫方可能立即等待。在事件處理程式到達等待表示式時,應用程式集中精力GetStringAsync的完成。事件處理程式等待AccessTheWebAsync,並且,AccessTheWebAsync 等待GetStringAsync

  7. GetStringAsync完成並生成一個字串結果。字串結果不通過對GetStringAsync 的呼叫返回方式與您可能期望的。(請確保方法返回已在第 3 步 .) 的任務,字串結果在表示方法的完成的任務,getStringTask儲存。等待運算子從getStringTask檢索結果。賦值語句將檢索的結果賦給urlContents

  8. GetStringAsync完成並生成一個字串結果。字串結果不通過對GetStringAsync 的呼叫返回方式與您可能期望的。(請確保方法返回已在第 3 步 .) 的任務,字串結果在表示方法的完成的任務,getStringTask儲存。等待運算子從getStringTask檢索結果。賦值語句將檢索的結果賦給urlContents

           如果您不熟悉非同步程式設計,請需要一分鐘考慮同步和非同步行為之間的差異。一個同步方法返回,其工作完成 (第 5 步),但是,非同步方法返回任務值,其工作掛起時 (第 3 步和第 6 步)。在非同步方法最終完成其工作時,任務將會標記為已完成和結果,如果有,在任務中。

          在什麼情況下可能想知道找到支援非同步程式設計的方法 (如GetStringAsync.NET Framework 4.5 包含與非同步以及等待的許多成員。您可以通過附加到成員名稱和Task 或的返回型別“Async”字尾識別這些成員。

       Windows 執行時 還包含您在 Windows 應用商店 apps 可以使用非同步和等待的許多方法。

執行緒

          非同步方法旨在成為非阻塞操作。當等待的任務執行時,在非同步方法的一個等待表示式不會阻止當前執行緒。相反,該表示式註冊該方法的其餘部分作為繼續並返回控制對非同步方法的呼叫方。

          非同步和等待關鍵字不會導致其他執行緒建立。因為非同步方法本身並不會執行的執行緒,非同步方法不需要多執行緒。只有 + 當方法處於活動狀態,則方法在當前同步上下文中執行並使用線上程的時間。可以使用 移動 CPU 工作移到後臺執行緒,但是,後臺執行緒不利於等待結果變得可用處理。

       以非同步程式設計的基於非同步的方法優於於幾乎每個用例的現有方法。具體而言,此方法比 IO 操作的 好,因為程式碼更為簡單的,因此無需防止爭用條件。與的組合,非同步程式設計的 CPU 操作的 好,因為非同步程式設計從Task.Run 傳輸到執行緒池的工作分隔執行您的程式碼以協調詳細資訊。

非同步和等待

如果指定使用 非同步非同步 修飾符,方法是非同步方法,可以實現以下兩個函式。

  • 清單非同步方法可以使用 Await 或指定的 等待 懸掛點。等待運算子通知編譯器非同步方法不能繼續點的過去,直到等待的非同步過程完成。同時,控制權交還非同步方法的呼叫方。

    一個非同步方法的備用在等待表示式的不構成從方法的退出,並且,finally 塊不會執行。

  • 清單非同步方法本身可以通過呼叫它的方法等待。

       非同步方法通常包含等待運算子的一個或多個匹配項,但是,請假等待表示式不會導致編譯器錯誤。如果非同步方法不會將等待運算子指示懸掛點,方法儘管"修飾符執行,一個同步方法。編譯器會發出此類方法的警告。

          AsyncasyncAwaitawait 是上下文關鍵字。

           在程式設計 .NET framework,非同步方法通常返回Task 或。在非同步方法中,等待運算子應用於從呼叫返回到另一個非同步方法的任務。

           您指定 ,因為返回型別,則方法包含指定型別TResult操作上的一個返回 (Visual Basic) 或返回 (c#) 語句。

使用 Task,因為返回型別,則該方法沒有返回語句或具有不返回操作執行緒的 return 語句。

        下面的示例演示如何宣告並呼叫返回 或Task的方法。

// 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();

        每個返回的任務表示正在進行的工作。任務封裝有關狀態的資訊非同步過程和,最後,從程序的最終結果或處理引發的異常;如果未成功。

        非同步方法也是 Sub 方法 (Visual Basic) 或使 void 返回型別 (c# 中)。這將返回型別主要用於定義事件處理程式,void 返回型別需要。非同步事件處理程式通常用作非同步程式的起始點。

        是 Sub 程式或具有 void 返回型別不能等待的非同步方法和一個無效返回的方法的呼叫方無法捕獲方法引發的任何異常。

在 Windows 執行時 程式設計的非同步 API 使之一返回型別,類似於任務:

命名約定

          按照約定,您追加“Async”傳遞給具有Asyncasync 修飾符方法的名稱。

       您可以忽略事件、基類或介面協定建議一個不同的名稱約定。例如,您不應向常用事件處理程式重新命名,例如Button1_Click

相關主題

完整的示例

          下面的程式碼是從本主題討論的 windows 演示基礎 (WPF) 應用程式的 MainWindow.xaml.vb 或 MainWindow.xaml.cs 檔案。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

// Add a using directive and a reference for System.Net.Http;
using System.Net.Http;

namespace AsyncFirstExample
{
    public partial class MainWindow : Window
    {
        // Mark the event handler with async so you can use await in it.
        private async void StartButton_Click(object sender, RoutedEventArgs e)
        {
            // Call and await separately.
            //Task<int> getLengthTask = AccessTheWebAsync();
            //// You can do independent work here.
            //int contentLength = await getLengthTask;

            int contentLength = await AccessTheWebAsync();

            resultsTextBox.Text +=
                String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
        }


        // Three things to note in the signature:
        //  - The method has an async modifier. 
        //  - The return type is Task or Task<T>. (See "Return Types" section.)
        //    Here, it is Task<int> because the return statement returns an integer.
        //  - The method name ends in "Async."
        async Task<int> AccessTheWebAsync()
        { 
            // You need to add a reference to System.Net.Http to declare client.
            HttpClient client = new HttpClient();

            // GetStringAsync returns a 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()
        {
            resultsTextBox.Text += "Working . . . . . . .\r\n";
        }
    }
}

// Sample Output:

// Working . . . . . . .

// Length of the downloaded string: 41564.

轉載自:http://msdn.microsoft.com/zh-cn/library/hh191443.aspx   (中文地址)

                http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx (英文地址) 中文翻譯的太爛了,如果英語不差的話,建議看英文。