距離微軟發佈Async CTP已經有幾個月了吧,周圍大家都在熱議着Async。如果你對Async已經非常熟悉,那麼,請直接略過……如果你跟我一樣,只會一點點異步編程,但又覺得以前的異步編程比較麻煩,那麼,讓我們一起來探索一下下一代的C#會給我們帶來什麼。(Async CTP同樣對VB有支持的。)
本文的例子基於Async CTP SP1 Refresh完成。由於 Async還處於CTP階段,很多東西還在討論,因此,也許待到C# 5.0發佈的時候,細節還會變動。但是,大體的思路,概念應該是不會有什麼變化了。
進入正題:
首先,要試用Async功能,我們需要安裝Visual Studio 2010 SP1和Microsoft Visual Studio Async CTP (SP1 Refresh)。
我們首先設定一個簡單的任務,分別來看一下,同步編程,利用回調進步異步編程和Async編程的方法,然後來通過他們來分析一下,Async到底是什麼,它給我們帶來了什麼。
任務:
建立一個Windows Form應用程序,當點擊按鈕時,先顯示一行字,例如,開始計算什麼的,用以表示狀態,然後計算從1到int.Max/2的累加,並把結果顯示出來。
同步我們會這麼做:
首先,寫一個函數來實現基本算法:
#region Do things |
然後,添加一個按鈕的Click事件處理程序:
privatevoid
btnSync_Click(object sender,EventArgs e) |
代碼第一行改寫Label的字樣;第二行調用算法獲得結果;第三行把結果輸出。看似挺不算的。運行一下,就會發現有兩個問題:
- 這個算法需要四五秒鐘左右的實現時間,並且在這幾秒鐘的時間裏,界面是鎖死的,也就是說應用程序就像死了一樣,它不接受任何用戶操作。(也許我的電腦比較差,呵呵,所以,如果你沒有遇到這種情況,請加大輸入參數的值,讓它算一會兒。)
- 我們沒有看到Start to do something這一行字。
OK,出現這個現象也是可以理解的,因爲我們把大量的運算添加到了UI線程裏面了。所以,解決方法就是把它放到外面。我試了一下不用Async,實現的代碼如下:
privatevoid
btnCallback_Click(object sender,EventArgs e) |
如果你覺得這段代碼比較暈,那就跳過這一節吧。可能我代碼寫得不好,大家將就看我簡單解釋一下,我首先給DoSomething寫了一個代理,然後,調用了代理的BeginInvoke方法,把算法放到了其它的Thread中去調用了。這個代理執行完了以後,因爲它不會直接返回一個long型的值,而是會去執行一個AsyncCallBack,所以,就在這個Callback裏,去調用這個代理的EndInvoke()。
好吧,且不論代碼質量,這個就是有Async之前的一種實現異步的方法。
從這個代碼裏,我們完全看不到原來代碼的影子,我也沒有辦法像解釋同步代碼一樣解釋:第一、第二、第三……有了Async之後呢?呵呵,代碼說明一切:
publicTask<long>
DoSomethingAsync(int n) |
三件事:
第一:添加文件引用:AsyncCtpLibrary.dll。相信Async正式發佈之後,這個會出現在.NET應用程序集裏。
第二:把DoSomething封裝成一個Task。
第三:添加一些關鍵字,例如async,例如await。
我們來仔細看一下代碼:
首先,我把要異步執行的代碼的返回值寫成Task<T>。這個返回值其實有三個選項:void,Task和Task<T>,具體怎麼用,大家查MSDN上C#4.0中的Task類吧。
然後,我調用了TaskEx中的Run<long>方法,傳遞給它一個返回值爲long的方法——就是我們的任務的算法啦。
如果你有興趣研究,可以看一下Run<T>其實調用了Task.Factory.StartNew<T>,而這個Start<New>則是先建了一個Task,然後調用了它的Start方法……
好,把算法封成任務部分完成。
第二部分代碼比較容易解釋了:
第一行改寫Label的字樣;第二行調用算法獲得結果;第三行把結果輸出。<--本行復制/粘貼自前文:-)
呵呵,讓我們看看細一點,比較一下Sync和Async的代碼:
Sync |
Async |
privatevoid
btnSync_Click(object sender,EventArgs e) |
privateasync
void btnAsync_Click(object sender,EventArgs
e) |
首先,我們在方法名上加上async修飾,聲明這是一個有異步調用的方法;
然後,我們在返回Task<T>的函數調用(DoSomethingAsync)之前添加一個await關鍵字。來猜猜看x是什麼類型的?答案是long型。有了await之後,即使在設計時,編譯器會自動把Task<T>的類型,轉換成T類型。
代碼到這裏結束了,但是,新的Async功能給我們帶來了什麼?是異步編程的能力嗎?我們用Callback同樣可以實現異步,而IAsyncCallback接口應該在.NET 1.1中已經實現了;多線程的命名空間也早就存在;Task在C# 4.0中被引入……
我想,Async給程序員帶來的是一種代碼邏輯爲中心並且實現多線程編程的方式。通過最後的比較,我們看到,Async的代碼與Sync的代碼相差無幾,程序不再需要花大量精力去考慮回調、同步等等的問題……這與C#一直在努力的方向是一致的,程序員更多的來描述是什麼而不是怎麼做。
最後,附上應用程序下載和源代碼,還有運行界面截圖……(好吧,我不是美工,請原諒 :-))
點擊Async,看到運行提示:
顯示執行結果:
最新最官方的Async資料在這兒:^v^
http://msdn.microsoft.com/Async
Little knowledge is dangerous.