https://www.youtube.com/watch?v=8vcrjhaF1zE
https://hiskio.com/courses/182/lectures/7553
範例:改成非同步呼叫
原本的 MyDownloadPage 是同步呼叫的寫法,底下是改成非同步呼叫的版本:
static async Task<string> MyDownloadPageAsync(string url)
{
var webClient = new WebClient();
Task<string> task = webClient.DownloadStringTaskAsync(url);
string content = await task;
return content;
}
光是方法簽名(signature)就有三處修改:
1.在宣告方法時,前面加上關鍵字 async,表示這是一個非同步方法,裡面會用到 await 關鍵字。
2.以 async 關鍵字宣告的方法若有回傳值,回傳的型別須以泛型 Task 表示。原先同步版本的方法是傳回 string,故此處改為 Task。非同步方法若不需要傳回值,則回傳型別應寫成 Task,而不要寫 void(原因後述)。
3.一般而言,非同步方法的名稱會以「Async」結尾,所以方法名稱現在改為MyDownloadPageAsync。
接著修改此方法的實作,把這行程式碼:
string content =
webClient.DownloadString(url);
改成這樣:
string content = await
webClient.DownloadStringAsync(url);
而這行程式碼也可以拆成兩行來寫:
Task<string> task = webClient.DownloadStringTaskAsync(url);
// (1)
string content = await task; // (2)
說明:
原本呼叫 WebClient 類別的 DownloadString 方法,現在改呼叫它提供的非同步版本:DownloadStringTaskAsync。與其他非同步 I/O 方法類似,DownloadStringTaskAsync 方法的內部會起始一個非同步 I/O 工作,而且不等該工作完成便立即返回呼叫端;此時傳回的物件是個 Task,代表一個將傳回 string 的非同步 I/O 工作。
使用 await 關鍵字來等待非同步工作執行完畢,然後取得其執行結果。這裡的「等待」,是採取「非同步等待」的作法。意思是說,使用了關鍵字 await 的地方會暫且記住 await 敘述所在的程式碼位置,並且令程式控制流程立刻返回呼叫端;等到 await 所等待的那個非同步工作執行完畢,控制流才又會切回來繼續執行剛才保留而未執行的程式碼。
接下來要修改的是 Main 函式:
static void Main(string[] args)
{
Task<string> task =
MyDownloadPageAsync("http://huan-lin.blogspot.com");
string content = task.Result; // 取得非同步工作的結果。
Console.WriteLine("網頁內容總共為 {0} 個字元。", content.Length);
Console.ReadKey();
}
這裡也是先取得非同步方法 MyDownloadPageAsync 所傳回的 Task 物件。但這一次是用 Task 的 Result 屬性來取得非同步工作的執行結果,而不是寫成 await task。其實這裡不能使用 await 關鍵字,因為有用到 await 的函式都必須在宣告時加上 async 關鍵字,否則無法通過編譯。
前面提過,「await 某件工作」的寫法會令控制流立刻返回呼叫端。相較之下,「讀取 Task 物件的 Result 屬性」則是阻斷式(blocking)操作,也就是說,它會令當前的執行緒暫停,直到欲等待的工作執行完畢並傳回結果之後,才繼續往下執行。
沒有留言:
張貼留言