1. 程式人生 > 其它 >非同步程式設計 async與await 關於Async與Await的FAQ

非同步程式設計 async與await 關於Async與Await的FAQ

原文連結:http://t.zoukankan.com/itjeff-p-4424810.html

原文連結:https://learn.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-version-history

C# 5.0 版

C# 版本 5.0 隨 Visual Studio 2012 (.Net Framework 4.5)一起釋出,是該語言有針對性的一個版本。

對此版本中所做的幾乎所有工作都歸入另一個突破性語言概念:適用於非同步程式設計的 async 和 await 模型。 下面是主要功能列表:

但是 async 和 await

 才是此版本真正的主角。

C# 在 2012 年推出這些功能時,將非同步引入語言作為最重要的組成部分,另現狀大為改觀。

如果你以前處理過冗長的執行操作以及實現回撥的 Web,應該會愛上這項語言功能。

先來看個傳統同步方法例子:

using System.Threading;
using System;

public class Program
{
    static void Main(string[] args)
    {
        // 同步方式
        Console.WriteLine("同步方式測試開始!");
        SyncMethod(0);
        Console.WriteLine(
"同步方式結束!"); Console.ReadKey(); } // 同步操作 private static void SyncMethod(int input) { Console.WriteLine("進入同步操作!"); var result = SyancWork(input); Console.WriteLine("最終結果{0}", result); Console.WriteLine("退出同步操作!"); } // 模擬耗時操作(同步方法) private
static int SyancWork(int val) { for (int i = 0; i < 5; ++i) { Console.WriteLine("耗時操作{0}", i); Thread.Sleep(100); val++; } return val; } }

結果:

可以從右圖中看到執行結果,是非常典型的同步執行方法。

async關鍵字能用在方法、lambda表示式的宣告部分,用來標示此方法可能包含await關鍵字,只有擁有async才能在其內部使用await關鍵字。

非同步方法可以具有Task、Task<>或void的返回型別;await關鍵字則是用於返回值是“可等待”型別(awaitable)的方法或lambda表示式內,“awaitable”可以是任何型別(常見的有Task、Task<>),它必須公開一個GetAwaiter() 方法並且返回有效的”awaiter”。

更詳細的資訊可以參考“關於Async與Await的FAQ”,裡面介紹了這些概念與注意事項。

當一個async方法,且內部包含await關鍵字,它就會在編譯的時候成為一個非同步方法,如果沒有await關鍵字,則它將只會被當成一個同步方法來執行。

如果對其內部實現感興趣可以參考“非同步效能:瞭解 Async 和 Await 的成本”一文,相信對深入瞭解這種機制還是有所幫助的。

現在我們嘗試使用新出的非同步關鍵字async、await來改造成非同步呼叫:

public class Program
{
    static void Main(string[] args)
    {
        // 非同步方式
        Console.WriteLine("非同步方式測試開始!");
        AsyncMethod(0);
        Console.WriteLine("非同步方式結束!");
        Console.ReadKey();
    }

    // 非同步操作
    private static async void AsyncMethod(int input)
    {
        Console.WriteLine("進入非同步操作!");
        var result = await AsyncWork(input);
        Console.WriteLine("最終結果{0}", result);
        Console.WriteLine("退出非同步操作!");
    }

    // 模擬耗時操作(非同步方法)
    private static async Task<int> AsyncWork(int val)
    {
        for (int i = 0; i < 5; ++i)
        {
            Console.WriteLine("耗時操作{0}", i);
            await Task.Delay(100);
            val++;
        }
        return val;
    }
}

結果:

 先來看結果吧,我們發現耗時操作已經是非同步進行了。

整體流程大概是先由Main函式非同步呼叫AsyncMethod,並不等待AsyncMethod完成,繼續往下執行。

而AsyncMethod方式在被呼叫後,在分配到時間片時開始啟動,執行函式體內容,並由於await AsyncWork語句而繼續非同步呼叫AsyncWork,但由於await關鍵字,將在此等待AsyncWork完成後,再繼續往下執行。

那麼,AyncWork也一樣的,被呼叫後,在分配到時間片時開始啟動,執行耗時操作。

可以看到,使用了新的關鍵字後,同步與非同步程式設計的語法差別進一步減少。

隨著.NET 4.5的推出,許多新類庫和既有類庫都支援這種新型的非同步語法(比如HttpClient、HttpServer、MemoryStream...),它們以類似ReadAsync、WriteAsync、SendAsync等分開方法來提供具有async宣告,且返回型別為Task、Task<>的非同步工作方式。

補充:

剛才有朋友提到await Task.Delay(100)這條語句,這是為了讓AsyncWork成為非同步方法才加的,如果你要進行的操作不支援await修飾怎麼辦,其實很簡單,使用Task.Factory.StartNew()就行了,舉例:

// 非同步操作
private static async void AsyncMethod(int input)
{
    Console.WriteLine("進入非同步操作!");
    var result = await Task.Factory.StartNew((Func<object, int>)SyncWork2, input);
    Console.WriteLine("最終結果{0}", result);
    Console.WriteLine("退出非同步操作!");
}

// 模擬耗時操作(同步方法)
private static int SyncWork2(object input)
{
    int val = (int)input;
    for (int i = 0; i < 5; ++i)
    {
        Console.WriteLine("耗時操作{0}", i);
        Thread.Sleep(100);
        val++;
    }
    return val;
}

這樣,我們的SyncWork2實際上卻是非同步執行的,所得結果與前面的非同步方法一致,只是這樣一來輸入引數只能是object型別,需要進行型別轉化。

另外,除了StartNew,我們還可以新建一個Task,然後呼叫Run,以完成同樣效果。

目前來說,這種非同步工作還是會造成本人使用上的不適,不過如果在將來的版本中,繼續推廣使用,相信不久便能熟練,且加快寫程式碼的速度,編寫出邏輯清晰的程式碼。

轉載請註明原址:http://www.cnblogs.com/lekko/archive/2013/03/05/2944282.html 

可以用以下程式碼進行async和await關鍵字的理解:

public class Program
{
    static void Main(string[] args)
    {
        // 非同步方式
        Console.WriteLine(" 非同步方式測試開始!");
        AsyncMethod(0);
        Console.WriteLine("非同步方式結束!");
        Console.ReadKey();
    }

    // 非同步操作
    private static async void AsyncMethod(int input)
    {
        Console.WriteLine("進入非同步操作!");
        var result = await AsyncWork(input);
        //var result = AsyncWork(input);
        Console.WriteLine("最終結果{0}", result);
        Console.WriteLine("退出非同步操作!");

        //await Fun2();

        for (int i = 0; i < 5; ++i)
        {
            Console.WriteLine("非同步操作中 -- {0}", i);
            await Task.Delay(200);
            //Task.Delay(100);
            //System.Threading.Thread.Sleep(500);
        }
    }

    // 模擬耗時操作(非同步方法)
    private static async Task<int> AsyncWork(int val)
    {
        for (int i = 0; i < 5; ++i)
        {
            Console.WriteLine("耗時操作前 - {0}", i);
            System.Threading.Thread.Sleep(500);
            val++;
        }

        for (int i = 0; i < 5; ++i)
        {
            Console.WriteLine("耗時操作{0}", i);
            await Task.Delay(500);
            //Task.Delay(100);
            //System.Threading.Thread.Sleep(500);
            val++;
        }
        return val;
    }

    private static async Task Fun2()
    {
        Console.WriteLine("Fun2 Start ...");
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine(i);
            await Task.Delay(500);
            //Task.Delay(500);
        }
        Console.WriteLine("Fun2 End ...");
    }
}

此程式碼可以證明,

1. 只聲明瞭async,方法體中沒有await的方法,執行時並不是非同步執行,它還是同步方法並同步執行。

要想方法是非同步方法,必須async和await聯合使用。只有聲明瞭async的方法在執行時碰到了await關鍵字時才會非同步執行,即此時會非同步執行該非同步方法呼叫程式碼後面的程式碼,如果方法體內沒有await關鍵字,則該方法還是同步方法,即同步執行。

2. 非同步方法如果有返回值,則需要Task<Type>,Type為放回型別,如返回型別為int,則為Task<int>。

如果該非同步方法沒有返回值,則使用void或Task, void只用在某個事件函式中呼叫非同步方法時,其他使用非同步方法的情況最好都用Task, 比如Main函式中要呼叫一個非同步方法,且該方法沒有返回值,則該非同步方法需要用void, 而在此非同步方法中呼叫了另一個非同步方法2,且該非同步方法2也沒有返回值,則該非同步方法2應該用Task.