国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

await使用中的阻塞和并發

2019-11-17 03:23:04
字體:
來源:轉載
供稿:網友

await使用中的阻塞和并發

2014-01-24 20:42 by 樓上那個蜀黍, ... 閱讀, ... 評論, 收藏, 編輯

好吧,不加點陳述不讓發首頁。那我們來陳述一下本篇提到的問題和對應的方法。

在.NET4.5中,我們可以配合使用async和await兩個關鍵字,來以寫同步代碼的方式,實現異步的操作。

好處我目前看來有兩點:

1.不會阻塞UI線程。一旦UI線程不能及時響應,會極大的影響用戶體驗,這點在手機和平板的APP上尤為重要。

2.代碼簡潔。

  • 相對基于event的異步方式,在多次回調的情況下(比如需要多次調web service,且后續調用基于前次調用的結果)特別明顯。可以將多個+=Completed方法合并到一起。
  • 相對于Begin/End的異步方式,避免了N重且不能對齊的大括號。

在同一個方法里存在多個await的情況下,如后續Async方法無需等待之前的Aysnc方法返回的結果,會隱式的以并行方式來運行后面的Async方法。

值得注意的是錯誤的寫法會導致非預期的阻塞,下文會以簡單的例子來討論在使用await的情況下,怎樣實現多個Task的并發執行。

我們這里先看幾個方法定義:

        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);        }

作用很簡單,僅僅是起到延遲的作用。我們再來看如下寫法的調用

            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.TheAwait(Visual Basic) orawait(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.

MSDN原文傳送門

到這里并沒有結束 ,后面還有一些奇怪的事情:

            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反編譯的結果&hellip;…我想說……沒看出來有什么區別……本篇先到這里。一旦琢磨出個所以然,我再發第二篇好了。

還恭請各位高人不吝賜教,多多提點。

補充:對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的背后到底發生了什么。我還要研究研究才能寫下一篇……

哈哈哈哈,干了件蠢事情……

代碼下載


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 寿宁县| 乡城县| 嘉荫县| 惠东县| 南溪县| 额尔古纳市| 秀山| 临夏县| 固镇县| 松桃| 富蕴县| 临江市| 察隅县| 北辰区| 方山县| 襄汾县| 纳雍县| 长武县| 滕州市| 南江县| 周至县| 昭觉县| 禄劝| 余江县| 杂多县| 辽阳县| 利川市| 姜堰市| 广平县| 隆林| 凤阳县| 孝感市| 昌平区| 岑巩县| 兴安县| 佛坪县| 鸡西市| 南阳市| 纳雍县| 大安市| 汉中市|