好吧,不加點陳述不讓發首頁。那咱們來陳述一下本篇提到的問題和對應的方法。html
在.NET4.5中,咱們能夠配合使用async和await兩個關鍵字,來以寫同步代碼的方式,實現異步的操做。web
好處我目前看來有兩點:併發
1.不會阻塞UI線程。一旦UI線程不能及時響應,會極大的影響用戶體驗,這點在手機和平板的APP上尤其重要。app
2.代碼簡潔。異步
在同一個方法裏存在多個await的狀況下,如後續Async方法無需等待以前的Aysnc方法返回的結果,會隱式的以並行方式來運行後面的Async方法。async
值得注意的是錯誤的寫法會致使非預期的阻塞,下文會以簡單的例子來討論在使用await的狀況下,怎樣實現多個Task的併發執行。優化
咱們這裏先看幾個方法定義:ui
static async Task Delay3000Async() { await Task.Delay(3000); Console.WriteLine(3000); Console.WriteLine(DateTime.Now); } static async Task Delay2000Async() { await Task.Delay(2000); Console.WriteLine(2000); Console.WriteLine(DateTime.Now); } static async Task Delay1000Async() { await Task.Delay(1000); Console.WriteLine(1000); Console.WriteLine(DateTime.Now); }
做用很簡單,僅僅是起到延遲的做用。咱們再來看以下寫法的調用spa
Console.WriteLine(DateTime.Now); new Action(async () => { await Delay3000Async(); await Delay2000Async(); await Delay1000Async(); })();
結果如圖,能夠看出3個await是線性執行,第一個await會返回並阻止接下來的await後面的方法。這應該不是咱們想要的效果,畢竟後面的方法並不依賴第一個方法的執行。線程
咱們換一種寫法,再運行一次程序:
var task3 = Delay3000Async(); var task2 = Delay2000Async(); var task1 = Delay1000Async(); new Action(async () => { await task3; await task2; await task1; })();
能夠看到3個await後面的方法是並行執行的。MSDN的解釋以下:
In an async method, tasks are started when they’re created. The Await (Visual Basic) or await (C#) operator is applied to the task at the point in the method where processing can’t continue until the task finishes.
However, you can separate creating the task from awaiting the task if your program has other work to accomplish that doesn’t depend on the completion of the task.
Between starting a task and awaiting it, you can start other tasks. The additional tasks implicitly run in parallel, but no additional threads are created.
到這裏並無結束 ,後面還有一些奇怪的事情:
var tasks = new List<Task> { Delay3000Async(), Delay2000Async(), Delay1000Async() }; tasks.ForEach(async _ => await _);
這個結果和上面是同樣的,能夠並行執行。這並不奇怪,咱們僅僅是把Task放到一個List裏,按照MSDN的說法,Task在被咱們放進List時就被建立,且併發執行了。
那麼咱們再來一個List,這回放進去的不是Task,而是Func<Task>:
var funcList = new List<Func<Task>>() { Delay3000Async, Delay2000Async, Delay1000Async }; funcList.ForEach(async _ => await _());
仍然能夠併發執行,看上去彷佛沒什麼問題,可是做爲Func<Task>來存儲到List裏,應該是沒有被建立出來纔對。爲何會可以併發呢?
咱們再來看最後一組寫法:
Func<Task> func3 = Delay3000Async; Func<Task> func2 = Delay2000Async; Func<Task> func1 = Delay1000Async; new Action(async () => { await func3(); await func2(); await func1(); } )();
意料之中的,以上的寫法並不可以作到併發執行。而是須要按順序執行func3,func2和func1。這很好解釋,由於: a task is awaited as soon as it’s created。咱們在建立Task以後當即就要求阻塞並等待完成才進行下一步。
寫到這裏的時候對List<Func<Task>>的例子開始迷糊了。參考了Reflector反編譯的結果……我想說……沒看出來有什麼區別……本篇先到這裏。一旦琢磨出個因此然,我再發第二篇好了。
還恭請各位高人不吝賜教,多多提點。
補充:對List<Func<Task>>的那個例子,我懷疑是Foreach這個擴展方法在偷偷作了優化。故增長了以下的試驗:
static async Task TestForeach() { var funcList = new List<Func<Task>>() { Delay3000Async, Delay2000Async, Delay1000Async }; foreach (var item in funcList) {
//這裏幹了件蠢事,不要主動阻塞在這裏,就能夠併發了…… await item(); } }
試驗結果代表用foreach來寫的話,確實是作不到並行執行的。那麼就須要去看一下Foreach的背後到底發生了什麼。我還要研究研究才能寫下一篇……
哈哈哈哈,幹了件蠢事情……