flutter-async和await原理解析

一 . async await 與 Future

在異步調(diào)用中有三個(gè)關(guān)鍵詞矫废,async岂膳、await、Future纳猫,其中async和await需要一起使用婆咸。在Dart中可以通過async和await進(jìn)行異步操作,async表示開啟一個(gè)異步操作续担,也可以返回一個(gè)Future結(jié)果擅耽。如果沒有返回值,則默認(rèn)返回一個(gè)返回值為null的Future物遇。

await的操作,不會影響方法外后續(xù)代碼的執(zhí)行;只會阻塞async方法的后續(xù)代碼

例子1
_testAsyncKeyword() {
    print("test函數(shù)開始了:${DateTime.now()}");
    _testString().then((value) => print(value));
    print("test函數(shù)結(jié)束了:${DateTime.now()}");
  }

  Future<String> _testString() async {
    Future f = Future.delayed(Duration(milliseconds: 300), () {
      return "我是測試字符串===1";
    });
    String result = await f;
    print("我是測試字符串===2");
    return result;
  }
// flutter: test函數(shù)開始了:2021-05-27 13:58:56.595964
// flutter: test函數(shù)結(jié)束了:2021-05-27 13:58:56.598801
// flutter: 我是測試字符串===2
// flutter: 我是測試字符串===1

在代碼示例中,執(zhí)行到_testString()方法,會同步進(jìn)入方法內(nèi)部進(jìn)行執(zhí)行憾儒,當(dāng)執(zhí)行到await時(shí)就會停止async內(nèi)部的執(zhí)行询兴,從而繼續(xù)執(zhí)行外面的代碼。所以await的操作起趾,不會影響后面代碼的執(zhí)行("test函數(shù)結(jié)束了"會先于_testString()內(nèi)部打印)诗舰。
當(dāng)await有返回后,會繼續(xù)從await的位置繼續(xù)執(zhí)行(所以先打印出了 "我是測試字符串===2" ,然后返回Future的結(jié)果,并通過print打印出 "我是測試字符串===1")训裆。

例子2
_testAsyncKeyword() async {
    print("test函數(shù)開始了:${DateTime.now()}");
    print(await _testString());
    print("test函數(shù)結(jié)束了:${DateTime.now()}");
  }

  Future<String> _testString() async {
    Future f = Future.delayed(Duration(milliseconds: 300), () {
      return "我是測試字符串===1";
    });
    String result = await f;
    print("我是測試字符串===2");
    return result;
  }

// flutter: test函數(shù)開始了:2021-05-27 14:06:48.185704
// flutter: 我是測試字符串===2
// flutter: 我是測試字符串===1
// flutter: test函數(shù)結(jié)束了:2021-05-27 14:06:48.497481

在代碼示例中, _testAsyncKeyword() 本身內(nèi)部就有一個(gè)await操作,當(dāng)執(zhí)行到await時(shí)就會停止_testAsyncKeyword() async內(nèi)部的執(zhí)行.等待_testString()有結(jié)果返回之后,繼續(xù)執(zhí)行.

_testString()內(nèi)部也是有一個(gè)await操作,當(dāng)執(zhí)行到await時(shí)就會停止_testString() async內(nèi)部的執(zhí)行,等待300毫秒,Future有結(jié)果后,打印字符串2

_testAsyncKeyword() 繼續(xù)執(zhí)行 打印 字符串1 及 結(jié)束

例子3
_testAsyncKeyword() {
    print("test函數(shù)開始了:${DateTime.now()}");
    firstString().then((value) => print(value));
    secondString().then((value) => print(value));
    thirdString().then((value) => print(value));
    print("test函數(shù)結(jié)束了:${DateTime.now()}");
  }

_testKeyword2() async{
    print("test函數(shù)開始了:${DateTime.now()}");
    print(await firstString());
    print(await secondString());
    print(await thirdString());
    print("test函數(shù)結(jié)束了:${DateTime.now()}");
  }
Future<String> firstString() {
    return Future.delayed(Duration(milliseconds: 300), () {
      return "我是一個(gè)字符串";
    });
  }

  Future<String> secondString() {
    return Future.delayed(Duration(milliseconds: 200), () {
      return "我是二個(gè)字符串";
    });
  }

  Future<String> thirdString() {
    return Future.delayed(Duration(milliseconds: 100), () {
      return "我是三個(gè)字符串";
    });
  }

//_testAsyncKeyword() 的打印:
//flutter: test函數(shù)開始了:2021-05-27 14:17:42.620409
//flutter: test函數(shù)結(jié)束了:2021-05-27 14:17:42.624359
//flutter: 我是三個(gè)字符串
//flutter: 我是二個(gè)字符串
//flutter: 我是一個(gè)字符串

//_testKeyword2() 的打印:
//flutter: test函數(shù)開始了:2021-05-27 14:18:41.401992
//flutter: 我是一個(gè)字符串
//flutter: 我是二個(gè)字符串
//flutter: 我是三個(gè)字符串
//flutter: test函數(shù)結(jié)束了:2021-05-27 14:18:42.027575

通過上面三個(gè)例子 , 大家應(yīng)該可以看出 await async 和 then之間的區(qū)別和聯(lián)系了吧.

二. async眶根、await的原理

async、await的操作屬于"假異步",這是為什么呢?
如果想要得到這個(gè)問題的答案,首先我們需要了解async边琉、await的原理属百,了解協(xié)程的概念,因?yàn)閍sync变姨、await本質(zhì)上就是協(xié)程的一種語法糖族扰。協(xié)程,也叫作coroutine,是一種比線程更小的單元渔呵。如果從單元大小來說怒竿,基本可以理解為 進(jìn)程->線程->協(xié)程

1.任務(wù)調(diào)度

在弄懂協(xié)程之前扩氢,首先要明白并發(fā)和并行的概念

  • 并發(fā): 指的是由系統(tǒng)來管理多個(gè)IO的切換耕驰,并交由CPU去處理。
  • 并行: 指的是多核CPU在同一時(shí)間里執(zhí)行多個(gè)任務(wù)录豺。

并發(fā)的實(shí)現(xiàn)由非阻塞操作+事件通知來完成朦肘,事件通知也叫做“中斷”。操作過程分為兩種巩检,一種是CPU對IO進(jìn)行操作厚骗,在操作完成后發(fā)起中斷告訴IO操作完成。另一種是IO發(fā)起中斷兢哭,告訴CPU可以進(jìn)行操作领舰。

線程: 本質(zhì)上也是依賴于中斷來進(jìn)行調(diào)度的,線程還有一種叫做“阻塞式中斷”迟螺,就是在執(zhí)行IO操作時(shí)將線程阻塞冲秽,等待執(zhí)行完成后再繼續(xù)執(zhí)行,通過單線程并發(fā)可以進(jìn)行大量并發(fā)操作。但線程的消耗是很大的矩父,并不適合大量并發(fā)操作的處理,且單個(gè)線程只能使用到單個(gè)CPU锉桑。當(dāng)多核CPU出現(xiàn)后,單個(gè)線程就無法很好的利用多核CPU的優(yōu)勢了窍株,所以又引入了線程池的概念民轴,通過線程池來管理大量線程。當(dāng)需要同時(shí)執(zhí)行多項(xiàng)任務(wù)的時(shí)候球订,我們就會采用多線程并發(fā)執(zhí)行.

單線程并發(fā) http://www.reibang.com/p/65e7f173024e

Dart單線程運(yùn)行模型: 輸入單吸納成運(yùn)行機(jī)制,主要是通過消息循環(huán)機(jī)制來實(shí)現(xiàn)任務(wù)調(diào)度和處理的.

2.協(xié)程coroutine

關(guān)于協(xié)程 https://zhuanlan.zhihu.com/p/172471249
多線程并發(fā) 操作系統(tǒng)在線程等待IO的時(shí)候后裸,會阻塞當(dāng)前線程,切換到其它線程冒滩,這樣在當(dāng)前線程等待IO的過程中微驶,其它線程可以繼續(xù)執(zhí)行。當(dāng)系統(tǒng)線程較少的時(shí)候沒有什么問題开睡,但是當(dāng)線程數(shù)量非常多的時(shí)候因苹,卻產(chǎn)生了問題。一是系統(tǒng)線程會占用非常多的內(nèi)存空間篇恒,二是過多的線程切換會占用大量的系統(tǒng)時(shí)間扶檐。
協(xié)程 運(yùn)行在線程之上,當(dāng)一個(gè)協(xié)程執(zhí)行完成后婚度,可以選擇主動讓出蘸秘,讓另一個(gè)協(xié)程運(yùn)行在當(dāng)前線程之上官卡。協(xié)程并沒有增加線程數(shù)量,只是在線程的基礎(chǔ)之上通過分時(shí)復(fù)用的方式運(yùn)行多個(gè)協(xié)程醋虏,而且協(xié)程的切換在用戶態(tài)完成寻咒,切換的代價(jià)比線程從用戶態(tài)到內(nèi)核態(tài)的代價(jià)小很多。

協(xié)程分為無線協(xié)程和有線協(xié)程.

  • 無線協(xié)程在離開當(dāng)前調(diào)用位置時(shí)颈嚼,會將當(dāng)前變量放在 堆區(qū)毛秘,當(dāng)再次回到當(dāng)前位置時(shí),還會繼續(xù)從堆區(qū)中獲取到變量阻课。所以叫挟,一般在執(zhí)行當(dāng)前函數(shù)時(shí)就會將變量直接分配到堆區(qū),而async限煞、await就屬于無線協(xié)程的一種抹恳。
  • 有線協(xié)程則會將變量繼續(xù)保存在 棧區(qū),在回到指針指向的離開位置時(shí)署驻,會繼續(xù)從棧中取出調(diào)用奋献。

3.async、await原理

之所以說async/await是假異步,是因?yàn)樗趫?zhí)行過程中并沒有開啟新的線程更沒有并發(fā)執(zhí)行,而是通過單線程上的任務(wù)調(diào)度(協(xié)程,沒有并發(fā)執(zhí)行功能)實(shí)現(xiàn)的:
當(dāng)代碼執(zhí)行到async則表示進(jìn)入一個(gè)協(xié)程旺上,會同步執(zhí)行async的代碼塊瓶蚂。async的代碼塊本質(zhì)上也相當(dāng)于一個(gè)函數(shù),并且有自己的上下文環(huán)境宣吱。當(dāng)執(zhí)行到await時(shí)窃这,則表示有任務(wù)需要等待,CPU則去調(diào)度執(zhí)行其他IO征候,也就是后面的代碼或其他協(xié)程代碼杭攻。過一段時(shí)間CPU就會輪詢一次,看某個(gè)協(xié)程是否任務(wù)已經(jīng)處理完成疤坝,有返回結(jié)果可以被繼續(xù)執(zhí)行朴上,如果可以被繼續(xù)執(zhí)行的話,則會沿著上次離開時(shí)指針指向的位置繼續(xù)執(zhí)行卒煞,也就是await標(biāo)志的位置。

由于并沒有開啟新的線程叼架,只是進(jìn)行IO中斷改變CPU調(diào)度畔裕,所以網(wǎng)絡(luò)請求這樣的異步操作可以使用async、await乖订,但如果是執(zhí)行大量耗時(shí)同步操作的話扮饶,應(yīng)該使用isolate開辟新的線程去執(zhí)行。

http://www.reibang.com/p/54da18ed1a9e

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末乍构,一起剝皮案震驚了整個(gè)濱河市甜无,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖岂丘,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陵究,死亡現(xiàn)場離奇詭異,居然都是意外死亡奥帘,警方通過查閱死者的電腦和手機(jī)铜邮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寨蹋,“玉大人松蒜,你說我怎么就攤上這事∫丫桑” “怎么了秸苗?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長运褪。 經(jīng)常有香客問我惊楼,道長,這世上最難降的妖魔是什么吐句? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任胁后,我火速辦了婚禮,結(jié)果婚禮上嗦枢,老公的妹妹穿的比我還像新娘攀芯。我一直安慰自己,他們只是感情好文虏,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布侣诺。 她就那樣靜靜地躺著,像睡著了一般氧秘。 火紅的嫁衣襯著肌膚如雪年鸳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天丸相,我揣著相機(jī)與錄音搔确,去河邊找鬼。 笑死灭忠,一個(gè)胖子當(dāng)著我的面吹牛膳算,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播弛作,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼涕蜂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了映琳?” 一聲冷哼從身側(cè)響起机隙,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蜘拉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后有鹿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旭旭,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年印颤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了您机。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡年局,死狀恐怖际看,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情矢否,我是刑警寧澤仲闽,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站僵朗,受9級特大地震影響赖欣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜验庙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一顶吮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧粪薛,春花似錦难审、人聲如沸蝶防。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽淮椰。三九已至昏名,卻和暖如春鼠次,著一層夾襖步出監(jiān)牢的瞬間撵溃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工掂咒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留才沧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓绍刮,卻偏偏與公主長得像糜工,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子录淡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 該文章屬于劉小壯原創(chuàng),轉(zhuǎn)載請注明:劉小壯[http://www.reibang.com/u/2de707c93d...
    劉小壯閱讀 30,120評論 12 86
  • Flutter默認(rèn)是單線程任務(wù)處理的油坝,如果不開啟新的線程嫉戚,任務(wù)默認(rèn)在主線程中處理刨裆。 事件隊(duì)列 和iOS應(yīng)用很像,在...
    羈擁_f357閱讀 579評論 0 1
  • 異步IO CPU的速度遠(yuǎn)遠(yuǎn)快于磁盤彬檀、網(wǎng)絡(luò)等IO帆啃。在一個(gè)線程中,CPU執(zhí)行代碼的速度極快窍帝,然而努潘,一旦遇到IO操作,如...
    時(shí)間之友閱讀 6,499評論 4 17
  • 一坤学、async/await的優(yōu)點(diǎn) 1)方便級聯(lián)調(diào)用:即調(diào)用依次發(fā)生的場景疯坤; 2)同步代碼編寫方式: Promise...
    puxiaotaoc閱讀 105,612評論 7 62
  • 16宿命:用概率思維提高你的勝算 以前的我是風(fēng)險(xiǎn)厭惡者,不喜歡去冒險(xiǎn)深浮,但是人生放棄了冒險(xiǎn)压怠,也就放棄了無數(shù)的可能。 ...
    yichen大刀閱讀 6,052評論 0 4