何為異步以及如何實(shí)現(xiàn)異步(C#)

說(shuō)明:本文只討論同步異步,以及異步的多線(xiàn)程實(shí)現(xiàn),不討論多線(xiàn)程導(dǎo)致的數(shù)據(jù)不同步問(wèn)題.

同步和異步是相對(duì)的 ?

在異步概念出來(lái)之前造虏,我們的代碼都是按同步的方式寫(xiě)的。簡(jiǎn)單來(lái)說(shuō)梁沧,就是程序嚴(yán)格按照代碼的邏輯次序起惕,一行一行執(zhí)行。一行代碼不走完不會(huì)執(zhí)行下一行代碼,當(dāng)一行代碼 特別耗時(shí)時(shí)就會(huì)造成阻塞,等待,造成的現(xiàn)象就是卡死.

異步就是為了解決這種阻塞而產(chǎn)生的,它是一種功能要求,說(shuō)異步是功能要求意味著它的實(shí)現(xiàn)可以有多種形式,只要解決阻塞的問(wèn)題就可以了.


舉例:

1.異步 I/O操作

I/O操作非常耗時(shí),但是在硬件層面上 硬盤(pán),顯卡和內(nèi)存是可以在不耗費(fèi)CPU資源的情況下進(jìn)行數(shù)據(jù)交換的.所以CPU可以控制硬盤(pán)和內(nèi)存之間的開(kāi)啟,且不用等待,當(dāng)資源交換完畢后回調(diào)給CPU就可以了 ,這就實(shí)現(xiàn)了異步,I/O流的異步操作是最常見(jiàn)的異步操作之一.

2.Unity中的協(xié)程(異步的單線(xiàn)程實(shí)現(xiàn))

Unity中的Coroutine旨在將一個(gè)函數(shù)分多次執(zhí)行,從而實(shí)現(xiàn)等同并發(fā)的處理方式,Coroutine可以用來(lái)實(shí)現(xiàn)異步,比如計(jì)時(shí)器(WaitForSeconds()),此外繼承CustomYieldInsruction可以實(shí)現(xiàn)更豐富的異步效果.

實(shí)現(xiàn)了計(jì)數(shù)100個(gè) 達(dá)成邏輯往下走的條件.?





3.異步不是多線(xiàn)程

前面說(shuō)到異步是一種功能要求,并且舉例了I/O流的異步和Unity協(xié)程的異步,I/O流的異步是硬件屬性實(shí)現(xiàn)的異步,Unity協(xié)程則是在主線(xiàn)程中對(duì)給定條件的判斷 決定是否執(zhí)行下一行代碼,而多線(xiàn)程則是另外一種異步的實(shí)現(xiàn)方式,因?yàn)楫惒胶投嗑€(xiàn)程總是被同時(shí)提到,且有迷惑性,所以又強(qiáng)調(diào)了下這個(gè)問(wèn)題.



C#中使用多線(xiàn)程實(shí)現(xiàn)異步


1.用C#語(yǔ)言提供的多線(xiàn)程實(shí)現(xiàn)異步,這里使用Task來(lái)實(shí)現(xiàn),主要使用await 和async. (主要原因是老版本的.net 多線(xiàn)程不太好懂,最初需要自己申請(qǐng)Thread,后來(lái)衍生出ThradPool允許開(kāi)發(fā)者申請(qǐng)線(xiàn)程池,但是還不夠好用).


Thread.Sleep()用來(lái)模擬耗時(shí)操作

Thread.CurrentThread.ManagedThreadId表示CLR提供的虛擬托管線(xiàn)程Id(用來(lái)判斷當(dāng)前方法在哪個(gè)線(xiàn)程被執(zhí)行)


先實(shí)現(xiàn)一下同步吧(不是說(shuō)大家不會(huì)哈)....用作和下文異步的對(duì)比


同步代碼

結(jié)果為:



異步的多線(xiàn)程實(shí)現(xiàn):

這里需要解釋下await關(guān)鍵字和async關(guān)鍵字

async用來(lái)修飾 方法,表示該方法可能會(huì)采取異步的方式運(yùn)行,修飾的方法必須void 或返回Task,Task<T>


await用來(lái)修飾 Task,Task<T> ,當(dāng)程序運(yùn)行遇到await時(shí)會(huì)跳出當(dāng)前方法繼續(xù)執(zhí)行主線(xiàn)程中的方法,并安排持續(xù)監(jiān)聽(tīng)它修飾的Task是否生成了結(jié)果,一旦生成結(jié)果,則再調(diào)回來(lái)繼續(xù)執(zhí)行修飾的Task下一行的代碼.并且可以用Task.result訪問(wèn)到它的結(jié)果


程序進(jìn)入await修飾的Task中后,如果方法中不存在await 則當(dāng)前是在同步執(zhí)行,執(zhí)行完該方法時(shí),接著await后面執(zhí)行. 如果修飾的Task中存在await 則在當(dāng)前線(xiàn)程中又申請(qǐng)了新的線(xiàn)程處理await后面的Task,這是一個(gè)循環(huán)的過(guò)程.

await修飾的Task中沒(méi)有await 則當(dāng)前執(zhí)行的是同步方法反之 await修飾的task是個(gè)異步Task ,則它就是異步方法 ,那么如何聲明一個(gè)異步的Task呢?

聲明一個(gè)異步的Task:

Task.Run();(多線(xiàn)程編程中有很多方法聲明異步Task,這里就放個(gè)最快實(shí)現(xiàn)的)

Task.Run的內(nèi)部代碼會(huì)占用線(xiàn)程池資源钓葫,并在一個(gè)可用的線(xiàn)程上與主線(xiàn)程并行運(yùn)行。


該代碼每個(gè)async修飾的方法中都有await,遇到await就跳出,task執(zhí)行完畢就回來(lái),所以Console.WriteLine(${“退出第{index}個(gè)方法”})一定是一個(gè)AsyncFunction中最后一個(gè)執(zhí)行的.結(jié)果為


若將上文的SimulateLongTimeFunction (index);?await修飾去掉 則???Console.WriteLine($"退出第{index}個(gè)方法");是for循環(huán)中每一輪結(jié)束的最后一句打印

如下圖:


可以看出耗時(shí)任務(wù)是最后執(zhí)行完畢的,別的代碼沒(méi)有await直接就跑完了

說(shuō)完了await就要提到另一個(gè)詞wait ,二者特別容易混淆,所以我想說(shuō)完同步異步和await之后再提wait的事 ?上文中模擬的耗時(shí)任務(wù)總是最后才完成.假如我要使用他們的結(jié)果,就必須等待他們都處理完畢 就可以用Task.Wait來(lái)等待結(jié)果,該方法是一個(gè)同步方法 ,所以它是阻塞的.

多線(xiàn)程編程會(huì)帶來(lái)數(shù)據(jù)沖突的問(wèn)題,盡管可以通過(guò)lock的方式避免數(shù)據(jù)沖突 但是,lock開(kāi)銷(xiāo)比較大.


2.Unity開(kāi)發(fā)中還可使用Unity提供的JobSystem實(shí)現(xiàn)異步

很多功能C#實(shí)現(xiàn)一次,Unity在其基礎(chǔ)上結(jié)合自己的使用場(chǎng)景又封裝一次這種操作還蠻常見(jiàn)的,比如C#的event和Unity的unityEvent等等.JobSystem的最小單位是Job,嗯聽(tīng)起來(lái)和Task差不多...

Unity號(hào)稱(chēng)JobSystem幫開(kāi)發(fā)者解決了很多痛點(diǎn),比如前面說(shuō)到的多線(xiàn)程數(shù)據(jù)沖突的問(wèn)題? 我也沒(méi)細(xì)研究過(guò)...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末票顾,一起剝皮案震驚了整個(gè)濱河市础浮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌奠骄,老刑警劉巖豆同,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異戚揭,居然都是意外死亡诱告,警方通過(guò)查閱死者的電腦和手機(jī)撵枢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)民晒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人锄禽,你說(shuō)我怎么就攤上這事潜必。” “怎么了沃但?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵磁滚,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我宵晚,道長(zhǎng)垂攘,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任淤刃,我火速辦了婚禮晒他,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘逸贾。我一直安慰自己陨仅,他們只是感情好津滞,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著灼伤,像睡著了一般触徐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上狐赡,一...
    開(kāi)封第一講書(shū)人閱讀 52,475評(píng)論 1 312
  • 那天撞鹉,我揣著相機(jī)與錄音,去河邊找鬼颖侄。 笑死孔祸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的发皿。 我是一名探鬼主播崔慧,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼穴墅!你這毒婦竟也來(lái)了惶室?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤玄货,失蹤者是張志新(化名)和其女友劉穎皇钞,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體松捉,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡夹界,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了隘世。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片可柿。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖丙者,靈堂內(nèi)的尸體忽然破棺而出复斥,到底是詐尸還是另有隱情,我是刑警寧澤械媒,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布目锭,位于F島的核電站,受9級(jí)特大地震影響纷捞,放射性物質(zhì)發(fā)生泄漏痢虹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一主儡、第九天 我趴在偏房一處隱蔽的房頂上張望奖唯。 院中可真熱鬧,春花似錦缀辩、人聲如沸臭埋。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瓢阴。三九已至畅蹂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間荣恐,已是汗流浹背液斜。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叠穆,地道東北人少漆。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像硼被,于是被迫代替她去往敵國(guó)和親示损。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361