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

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

await使用中的阻塞和并發(二)

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

await使用中的阻塞和并發(二)

2014-01-27 11:18 by 樓上那個蜀黍, ... 閱讀, ... 評論, 收藏, 編輯

  本文繼續上篇未完成的討論,通過將Lambda還原成最普通的代碼段,來解釋上篇提出的疑問。并更正上篇中一些不太正確的寫法。最后會給出無需等待Async方法返回值時,對Async方法使用await的建議,供大家參考。

  第一篇傳送門:await使用中的阻塞和并發

  首先我們比較以下三段代碼,其中第一和第三可以做到并發執行,第二個是線性的執行。

        //并發        public async Task Await3Task()        {            var task3 = Delay3000Async();            var task2 = Delay2000Async();            var task1 = Delay1000Async();            await task3;            await task2;            await task1;        }        //非并發        public async Task Await3DelayAsync()        {            await Delay3000Async();            await Delay2000Async();            await Delay1000Async();        }        //并發,這里甚至可以把var task3等去掉,直接調用xxxAsync(),只是會出現警告的波浪罷了        public void NoAwait3Task()        {            var task3 = Delay3000Async();            var task2 = Delay2000Async();            var task1 = Delay1000Async();        }
        //這里補充一下調用的三個Async方法     public async Task Delay3000Async()        {            await Task.Delay(3000);            Console.WriteLine(3000);            Console.WriteLine(DateTime.Now);        }        public async Task Delay2000Async()        {            await Task.Delay(2000);            Console.WriteLine(2000);            Console.WriteLine(DateTime.Now);        }        public async Task Delay1000Async()        {            await Task.Delay(1000);            Console.WriteLine(1000);            Console.WriteLine(DateTime.Now);        }

  這里我們可以看出,await和并發木有關系,隱式的并發執行是由async方法決定的。而await是用于主動的阻塞,期望等待方法結束才繼續運行時使用。

  以下2個方法的執行結果是一樣的,都可以并發執行。可以看出,把僅僅希望并發執行,不需要返回結果的方法丟到List里,然后Foreach是毫無意義的……所以上篇其實是干了一些蠢事情……

        public void AwaitTaskList()        {            var tasks = new List<Task>            {                Delay3000Async(),                Delay2000Async(),                Delay1000Async()            };            tasks.ForEach(async _ => await _);        }        public void NoAwaitTaskList()        {            var tasks = new List<Task>            {                Delay3000Async(),                Delay2000Async(),                Delay1000Async()            };        }

  上篇提到Task在創建的時候,就已經開始運行了。而await僅僅是出現在需要等待結果的地方。所以如果無需等待,就不要寫await了……貌似上篇又干了一些蠢事……

        //非并發        public async Task Await3Func()        {            Func<Task> func3 = Delay3000Async;            Func<Task> func2 = Delay2000Async;            Func<Task> func1 = Delay1000Async;            await func3();            await func2();            await func1();        }        //并發        public void NoAwait3Func()        {            Func<Task> func3 = Delay3000Async;            Func<Task> func2 = Delay2000Async;            Func<Task> func1 = Delay1000Async;            func3();            func2();            func1();        }

  同時我本人對List<Func<Task>>尚未創建Task卻可以并發表示疑問,接下來給出解答。下面分別貼出了使用Lambda和不使用的情況。我們可以清楚的看到Lambda表達式具體幫我們省略了什么。

        //使用Lambda        public void AwaitFuncTaskList()        {            var funcList = new List<Func<Task>>()            {                Delay3000Async,                Delay2000Async,                Delay1000Async            };            funcList.ForEach(async _ => await _());        }        //不使用Lambda        public void AwaitFuncTaskListNoLambda()        {            var funcList = new List<Func<Task>>()            {                Delay3000Async,                Delay2000Async,                Delay1000Async            };            //funcList.ForEach(AwaitAction());            foreach(var func in funcList)            {                AwaitAction()(func);            }        }        public Action<Func<Task>> AwaitAction()        {            return async _ => await _();        }

  根據上文的總結,可以看出雖然await造成了阻塞,但并不是在主線程等待,所以我們幸運的并發了……

  再看下面一段,我干脆拿掉了await,毫無疑問的并發執行了。上篇讓人汗顏的事情貌似還干了不少,好在我臉皮厚,不會刪掉前一篇的隨筆,哈哈哈哈……

        public void NoAwaitFuncTaskList()        {            var funcList = new List<Func<Task>>()            {                Delay3000Async,                Delay2000Async,                Delay1000Async            };            funcList.ForEach(_ => _());        }        public void NoAwaitFuncTaskListNoLambda()        {            var funcList = new List<Func<Task>>()            {                Delay3000Async,                Delay2000Async,                Delay1000Async            };            //funcList.ForEach(NoAwaitAction());            foreach(var func in funcList)            {                NoAwaitAction()(func);            }        }        public Action<Func<Task>> NoAwaitAction()        {            return _ => _();        }

  仔細看一下可以發現,為了懶惰而使用的ForEach其實增加了多余的一層Action<Func<Task>>,如果直接使用foreach會是如下的情況:

        public void NoAwaitFuncTaskWithoutForeachExtension()        {            var funcList = new List<Func<Task>>()            {                Delay3000Async,                Delay2000Async,                Delay1000Async            };            foreach (var func in funcList)            {                func();            }        }

  接下來是總結陳述:

  1.   async用于異步,可以優美的替代Thread、BackgroundWorker和Task.Run等寫法。
  2.   await用于等待。一定是在你主動希望阻塞并等待返回結果時才使用。
  3.   在async方法里,Task在創建時就開始運行了。
  4.   寫Lamdba別把自己寫暈了……

  代碼下載


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 乌拉特前旗| 襄樊市| 怀仁县| 南开区| 芮城县| 本溪| 泸定县| 历史| 定结县| 平凉市| 印江| 丽江市| 临湘市| 中方县| 建昌县| 辽源市| 东兰县| 霍邱县| 盖州市| 达孜县| 曲麻莱县| 阿拉善右旗| 遂宁市| 徐州市| 崇明县| 承德县| 武川县| 久治县| 龙胜| 云安县| 驻马店市| 杭州市| 北川| 河池市| 昭苏县| 五寨县| 太原市| 崇文区| 永宁县| 南充市| 河池市|