Dart多個(gè)future隊(duì)列完成加入順序關(guān)系及原子性論證
引言
Dart 是一個(gè)在單線程中運(yùn)行的程序。在程序中執(zhí)行一個(gè)需要長時(shí)間的執(zhí)行的操作,為避免卡住UI主線程,我們會(huì)用到異步(future),可以使程序在等待一個(gè)耗時(shí)操作完成時(shí)繼續(xù)處理其他工作。
在進(jìn)入正題之前,我們先了解一下 Dart 的消息循環(huán)機(jī)制:
- Dart 從兩個(gè)隊(duì)列執(zhí)行任務(wù):Event事件隊(duì)列 和 Microtask微任務(wù)隊(duì)列
- 事件循環(huán)會(huì)優(yōu)先處理微任務(wù)隊(duì)列,microtask清空之后才將 event事件隊(duì)列中的下一個(gè)項(xiàng)目出隊(duì)并處理
- 事件隊(duì)列具有來自Dart(Future,Timer,Isolate Message等)和系統(tǒng)(用戶輸入,I/O等)
- 微任務(wù)隊(duì)列目前僅包含來自Dart,當(dāng)然我們也可以自己往微隊(duì)列中插入任務(wù)
什么是 Future
Future 是什么?這里我們用小篇幅簡(jiǎn)單描述一下。future是一個(gè)異步的執(zhí)行操作,可以在不阻塞代碼的情況下實(shí)現(xiàn)耗時(shí)功能。
main() { Future(() { print('我是一個(gè)耗時(shí)操作'); }).then((value){ print('future 結(jié)束了'); }); print('main'); }
//打印結(jié)果
main
我是一個(gè)耗時(shí)操作
future 結(jié)束了
在項(xiàng)目中,我們使用 Future
、Async
、await
相互組合實(shí)現(xiàn)異步編碼。
Future 操作具備'原子性'嗎
上面的篇幅我們說過,future 創(chuàng)建后會(huì)被直接加入到事件隊(duì)列依次執(zhí)行。那么在上一個(gè) future 在沒有標(biāo)識(shí)完成前,下一個(gè) future 可以被執(zhí)行嗎?
小編寫了幾個(gè)樣例來做實(shí)驗(yàn):
實(shí)驗(yàn)寫法一:
main() { Test1.future1().then((value) => print(value)); Test1.future2().then((value) => print(value)); } abstract class Test1 { static Future<String> future1() async { return Future(() async { print('開始 future1'); await TestTool.timeConsume(1000000000); //耗時(shí)運(yùn)算 print('一千年過去了'); return 'future1 結(jié)束了'; }); } static Future<String> future2() async { return Future(() async { print('開始 future2'); await TestTool.timeConsume(1000); //耗時(shí)運(yùn)算 print('繼續(xù) future2'); return 'future2 結(jié)束了'; }); } }
//打印結(jié)果
開始 future1
一千年過去了
future1 結(jié)束了
開始 future2
繼續(xù) future2
future2 結(jié)束了
實(shí)驗(yàn)結(jié)果:
- 從打印結(jié)果上看,future任務(wù)沒有中斷,執(zhí)行完當(dāng)前任務(wù)后才可執(zhí)行隊(duì)列中的下一個(gè)future
實(shí)驗(yàn)寫法二:
main() { Test2.future1().then((value) => print(value)); Test2.future2().then((value) => print(value)); } abstract class Test2 { static Future<String> future1() async { print('開始 future1'); await TestTool.timeConsume(1000000000);//耗時(shí)運(yùn)算 print('一千年過去了'); return 'future1 結(jié)束了'; } static Future<String> future2() async { print('開始 future2'); await TestTool.timeConsume(1000);//耗時(shí)運(yùn)算 print('繼續(xù) future2'); return 'future2 結(jié)束了'; } }
//打印結(jié)果
開始 future1
開始 future2
一千年過去了
future1 結(jié)束了
繼續(xù) future2
future2 結(jié)束了
實(shí)驗(yàn)結(jié)果:
- future2在future1沒有結(jié)束前就已經(jīng)開始了任務(wù)。
- future2會(huì)在future1任務(wù)執(zhí)行完成后響應(yīng)結(jié)束,整個(gè)過程仍然保持了完成順序與加入事件隊(duì)列的順序一致性。
實(shí)驗(yàn)寫法三:
main() { Test3.future1().then((value) => print(value)); Test3.future2().then((value) => print(value)); } abstract class Test3 { static Future<String> future1() async { print('開始 future1'); await Future(() => TestTool.timeConsume(1000000000));//耗時(shí)運(yùn)算 print('一千年過去了'); return 'future1 結(jié)束了'; } static Future<String> future2() async { print('開始 future2'); await TestTool.timeConsume(1000);//耗時(shí)運(yùn)算 print('繼續(xù) future2'); return 'future2 結(jié)束了'; } }
//打印結(jié)果
開始 future1
開始 future2
繼續(xù) future2
future2 結(jié)束了
一千年過去了
future1 結(jié)束了
實(shí)驗(yàn)結(jié)果:
- 從打印結(jié)果上看,future1開始后,future2直接開始任務(wù),且future2任務(wù)完成后直接標(biāo)識(shí)完成。
- future1 和 future2 的完成順序已經(jīng)和加入事件隊(duì)列的順序無關(guān)了,只與內(nèi)部耗時(shí)正相關(guān)。
附上耗時(shí)代碼:
abstract class TestTool { ///耗時(shí)操作 static Future<int> timeConsume(int num) async { final result = _timeConsume(num); return result; } static int _timeConsume(int num) { int count = 0; while (num > 0) { if (num % 2 == 0) { count++; } num--; } return count; } }
論證結(jié)論
綜合上述三種寫法分析:
future方法體內(nèi)部不屬于可靠的'原子性操作',不同的寫法有不同的差異性。 如果想將整個(gè)方法體內(nèi)部作為不可拆分的執(zhí)行單位。在外層使用Future進(jìn)行包裹處理,如寫法一中Test1示例:
static Future<T> funcName() async { return Future(() async { ... 具體的方法體內(nèi)容 ... return result; }); }
future在創(chuàng)建的同時(shí),就會(huì)被加入到event事件隊(duì)列中。事件隊(duì)列是依次執(zhí)行的,但每個(gè)future的完成順序與加入的順序不存在可靠的一致性。 如果在業(yè)務(wù)內(nèi)想保持順序的一致性,可參考上述寫法,或使用 await
進(jìn)行強(qiáng)制等待如:
main() async { await Test2.future1().then((value) => print(value)); Test2.future2().then((value) => print(value)); }
這樣寫,future2 就一定會(huì)在 future1 執(zhí)行完成后才進(jìn)入開始狀態(tài)。
以上就是Dart多個(gè)future隊(duì)列完成加入順序關(guān)系及原子性論證的詳細(xì)內(nèi)容,更多關(guān)于Dart多個(gè)future原子性的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Dart語法之變量聲明與數(shù)據(jù)類型實(shí)例詳解
這篇文章主要為大家介紹了Dart語法之變量聲明與數(shù)據(jù)類型實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10Flutter入門學(xué)習(xí)Dart語言變量及基本使用概念
這篇文章主要為大家介紹了Flutter入門學(xué)習(xí)Dart語言變量及基本使用概念,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09flutter中如何使用和擴(kuò)展ThemeData實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了flutter中如何使用和擴(kuò)展ThemeData實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11Flutter學(xué)習(xí)筆記(一)配置環(huán)境
這篇文章主要介紹了Flutter學(xué)習(xí)筆記(一)配置環(huán)境,Flutter?app使用了?Dart語言,源自于?Google,現(xiàn)在是?ECMA?的標(biāo)準(zhǔn),需要的朋友可以參考下2023-04-04Android開發(fā)中Dart語言7個(gè)很酷的特點(diǎn)
這篇文章主要為大家介紹了Android開發(fā)中Dart語言7個(gè)很酷的特點(diǎn)分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05