1. 程式人生 > >async & await 的前世今生

async & await 的前世今生

async 和 await 出現在C# 5.0之後,給並行程式設計帶來了不少的方便,特別是當在MVC中的Action也變成async之後,有點開始什麼都是async的味道了。但是這也給我們程式設計埋下了一些隱患,有時候可能會產生一些我們自己都不知道怎麼產生的Bug,特別是如果連執行緒基礎沒有理解的情況下,更不知道如何去處理了。那今天我們就來好好看看這兩兄弟和他們的叔叔(Task)爺爺(Thread)們到底有什麼區別和特點,本文將會對Thread 到 Task 再到 .NET 4.5的 async和 await,這三種方式下的並行程式設計作一個概括性的介紹包括:開啟執行緒,執行緒結果返回,執行緒中止,執行緒中的異常處理等。

內容索引

建立

123456789 staticvoidMain(){newThread(Go).Start();// .NET 1.0開始就有的 Task.Factory.StartNew(Go);// .NET 4.0 引入了 TPLTask.Run(newAction(Go));// .NET 4.5 新增了一個Run的方法}publicstaticvoidGo(){Console.WriteLine("我是另一個執行緒");}

這裡面需要注意的是,建立Thread的例項之後,需要手動呼叫它的Start方法將其啟動。但是對於Task來說,StartNew和Run的同時,既會建立新的執行緒,並且會立即啟動

它。

執行緒池

執行緒的建立是比較佔用資源的一件事情,.NET 為我們提供了執行緒池來幫助我們建立和管理執行緒。Task是預設會直接使用執行緒池,但是Thread不會。如果我們不使用Task,又想用執行緒池的話,可以使用ThreadPool類。

12345678910 staticvoidMain(){Console.WriteLine("我是主執行緒:Thread Id {0}",Thread.CurrentThread.ManagedThreadId);ThreadPool.QueueUserWorkItem(Go);Console.ReadLine();}publicstaticvoidGo(objectdata){Console.WriteLine("我是另一個執行緒:Thread Id {0}",Thread.CurrentThread.ManagedThreadId);}

傳入引數

1234567891011121314151617181920212223 staticvoidMain(){newThread(Go).Start("arg1");// 沒有匿名委託之前,我們只能這樣傳入一個object的引數newThread(delegate(){// 有了匿名委託之後...GoGoGo("arg1","arg2","arg3");});newThread(()=>{// 當然,還有 LambadaGoGoGo("arg1","arg2","arg3");}).Start();Task.Run(()=>{// Task能這麼靈活,也是因為有了Lambda呀。GoGoGo("arg1","arg2","arg3");});}publicstaticvoidGo(objectname){// TODO}publicstaticvoidGoGoGo(stringarg1,stringarg2,stringarg3){// TODO}

返回值

Thead是不能返回值的,但是作為更高階的Task當然要彌補一下這個功能。

12345 staticvoidMain(){// GetDayOfThisWeek 執行在另外一個執行緒中vardayName=Task.Run(()=>{returnGetDayOfThisWeek();});Console.WriteLine("今天是:{0}",dayName.Result);}

共享資料

上面說了引數和返回值,我們來看一下執行緒之間共享資料的問題。

123456789101112 privatestaticbool_isDone=false;staticvoidMain(){newThread(Done).Start();newThread(Done).Start();}staticvoidDone(){if(!_isDone){_isDone=true;// 第二個執行緒來的時候,就不會再執行了(也不是絕對的,取決於計算機的CPU數量以及當時的執行情況)Console.WriteLine("Done");}}

執行緒之間可以通過static變數來共享資料。

執行緒安全

我們先把上面的程式碼小小的調整一下,就知道什麼是執行緒安全了。我們把Done方法中的兩句話對換了一下位置 。

12345678910111213 privatestaticbool_isDone=false;staticvoidMain(){newThread(Done).Start();newThread(Done).Start();Console.ReadLine();}staticvoidDone(){if(!_isDone){Console.WriteLine("Done");// 猜猜這裡面會被執行幾次?_isDone=true;}}

上面這種情況不會一直髮生,但是如果你運氣好的話,就會中獎了。因為第一個執行緒還沒有來得及把_isDone設定成true,第二個執行緒就進來了,而這不是我們想要的結果,在多個執行緒下,結果不是我們的預期結果,這就是執行緒不安全。

要解決上面遇到的問題,我們就要用到鎖。鎖的型別有獨佔鎖,互斥鎖,以及讀寫鎖等,我們這裡就簡單演示一下獨佔鎖。

12345678910111213141516 privatestaticbool_isDone=false;privatestaticobject_lock=newobject();staticvoidMain(){newThread(Done).Start();newThread(Done).Start();Console.ReadLine();}staticvoidDone(){lock(_lock){if(!_isDone){Console.WriteLine("Done");// 猜猜這裡面會被執行幾次?_isDone=true;}}}

再我們加上鎖之後,被鎖住的程式碼在同一個時間內只允許一個執行緒訪問,其它的執行緒會被阻塞,只有等到這個鎖被釋放之後其它的執行緒才能執行被鎖住的程式碼。

Semaphore 訊號量

我實在不知道這個單詞應該怎麼翻譯,從官方的解釋來看,我們可以這樣理解。它可以控制對某一段程式碼或者對某個資源訪問的執行緒的數量,超過這個數量之後,其它的執行緒就得等待,只有等現在有執行緒釋放了之後,下面的執行緒才能訪問。這個跟鎖有相似的功能,只不過不是獨佔的,它允許一定數量的執行緒同時訪問。

123 staticSemaphoreSlim _sem=newSemaphoreSlim(3);// 我們限制能同時訪問的執行緒數量是3staticvoidMain(){for(inti=1;i

在最開始的時候,前3個排隊之後就立即進入執行,但是4和5,只有等到有執行緒退出之後才可以執行。

異常處理

其它執行緒的異常,主執行緒可以捕獲到麼?

12345678910 publicstaticvoidMain(){try{newThread(Go).Start();}catch(Exception ex){// 其它執行緒裡面的異常,我們這裡面是捕獲不到的。Console.WriteLine("Exception!");}}staticvoidGo(){thrownull;}

那麼升級了的Task呢?

12345678910111213141516 publicstaticvoidMain(){try{vartask=Task.Run(()=>{Go();});task.Wait();// 在呼叫了這句話之後,主執行緒才能捕獲task裡面的異常// 對於有返回值的Task, 我們接收了它的返回值就不需要再呼叫Wait方法了// GetName 裡面的異常我們也可以捕獲到vartask2=Task.Run(()=>{returnGetName();});varname=task2.Result;}catch(Exception ex){Console.WriteLine("Exception!");}}staticvoidGo(){thrownull;}staticstringGetName(){thrownull;}

一個小例子認識async & await

1234567891011121314151617181920 staticvoidMain(string[]args){Test();// 這個方法其實是多餘的, 本來可以直接寫下面的方法// await GetName()  // 但是由於控制檯的入口方法不支援async,所有我們在入口方法裡面不能 用 awaitConsole.WriteLine("Current Thread Id :{0}",Thread.CurrentThread.ManagedThreadId);}staticasync Task Test(){// 方法打上async關鍵字,就可以用await呼叫同樣打上async的方法// await 後面的方法將在另外一個執行緒中執行await GetName(

相關推薦

async&await前世今生

amp efault nco void compiler ges -s lis private async&await=custom IAsyncStateMachineasync&await是IAsyncStateMachine的語法糖 驗證 分別使用as

async & await前世今生

async 和 await 出現在C# 5.0之後,給並行程式設計帶來了不少的方便,特別是當在MVC中的Action也變成async之後,有點開始什麼都是async的味道了。但是這也給我們程式設計埋下了一些隱患,有時候可能會產生一些我們自己都不知道怎麼產生的Bug,特別是如果連執行緒基礎沒有理解的情況下,更

async await Task

對象 hello cnblogs using 指定 順序 arp 等待 con 一、使用Task 引用命名空間 using System.Threading.Tasks; 1.工廠方式 Task.Factory.StartNew(() => {Console.W

[轉載]持續交付和DevOps的前世今生

db2 新的 提醒 策略 mes 上線 線上 解決 項目 作者/分享人:喬梁,20年IT老兵,騰訊公司高級管理顧問,敏捷和精益開發專家,持續交付領域先行者。曾就職於百度,國內多個知名互聯網公司的企業教練。 歷年QCon技術大會的講師和專題出品人。 這是一個新概念風起雲

async await的使用

con span sleep 使用 color console syn start nbsp var sleep = function (time) { return new Promise(function (resolve, reject) {

[Node] Catch error for async await

mongodb color def .post direct express cnblogs err n) When we try to do MongoDB opration, mongoose return Promise, we can use async/await

async await promise

log 也有 ons new 一行代碼 ole nbsp blog 沒有 async 異步函數,以後可能會用得很廣。 1、箭頭函數: 沒有{}時不寫return 也有返回值 2、Promise : 異步神器,很多異步api都是基於Promise 3、new Promise(

阿拉丁小程序生態課7月開課,解讀小程序的“前世今生

二維 鳳凰網 jic 資源 創業 web 動力 數據 part 阿拉丁小程序生態課·北京站將於7月8日13:30-17:30在北京京糧大廈四層方糖小鎮舉行,開課前期工作正在緊鑼密鼓籌備中。會務方透露,本次生態課將從小程序對O2O商業帶來的變革、小程序未來的發展、以及小程序如

理解ES7中的async/await

def 需求 一個表 來看 1-1 運算符 get 執行 表達 理解ES7中的async/await 優勢是:就是解決多層異步回調的嵌套  從字面上理解 async/await, async是 "異步"的含義,await可以認為是 async wait的簡寫,因此

websocke前世今生

模擬 easy web開發 浪費 rtt row 實現 htm read 註:以下內容來自網上。本人經過加工整理。 1、問什麽要用websocke? Browser已經支持http協議,為什麽還要開發一種新的WebSocket協議呢?我們知道http協議是一種單

TWaver可視化編輯器的前世今生(四)電力 雲計算 數據中心

變電站 fontsize 復雜 部署 ood 配置信息 來看 tar 右鍵 插播一則廣告(長期有效) TWaver需要在武漢招JavaScript工程師若幹 要求:對前端技術(JavasScript、HTML、CSS),對可視化技術(Canvas、WebGL)有濃厚的興

C# Async Await

ati style ren console man stat tel current spa #region Async、Await static void Async() { Async1();

ES7 Async/Await 陷阱

average 模式 時間 eth 復雜 簡化 同時 不同的 then 什麽是Async/Await ES6新增了Promise函數用於簡化項目代碼流程。然而在使用promise時,我們仍然要使用callback,並且並不知道程序要幹什麽,例如: function doS

SQLMap的前世今生(Part1)

節點 如何 所在 having image character mysql 最大 格式 http://www.freebuf.com/sectool/77948.html 一、前言 談到SQL註入,第一時間就會想到神器SQLMAP,SQLMap是一款用來檢測與利用的SQ

【轉】DevOps的前世今生

data 關系 國外 應用服務 單位 graph 組織 收集 良好的 轉自:http://www.infoq.com/cn/news/2016/09/learn-devops-from-reports 目前在國外,互聯網巨頭如Google、Facebook、Amazon、L

JavaScript 的 async/await

處理 這也 現在 err 並且 舉例 block opera script 隨著 Node 7 的發布,越來越多的人開始研究據說是異步編程終級解決方案的 async/await。 異步編程的最高境界,就是根本不用關心它是不是異步。 async 函數就是隧道盡頭的亮光,很多人

Lambda表達式的前世今生~~~~~~

{0} nor 方法 lam 一個 lamdba spa 現在 ace namespace MyLamdba{ class Program { static void Main(string[] args) {

字符編碼的前世今生--轉

tab 當前 小端模式 成本 這一 mat port discover 演進 原文地址:http://gitbook.cn/books/599d075614d1bc13375caeaf/index.html 前言 很多程序員對字符編碼不太理解,雖然他們大概知道 ASCI

WebP 的前世今生

視頻格式 也有 同時 無損壓縮 得到 閱讀 大小 firefox 並且 除了視頻,圖片占據了 PC 和 App 的大部分流量,為運營方帶來高額的成本支出,同時過多的圖片加載會影響到網站與 App 的加載速度。因此在保證圖片質量的前提下縮小圖片的體積就成了迫在眉睫的事情。 目

async, await運用

{} 函數聲明 並行 his const promise code 中斷 async 1.async 函數聲明及調用方式: 1 // async 函數聲明,調用 2 const a1 = async() => { 3 console.log("this