網站首頁 編程語言 正文
引言
Dart 是一個在單線程中運行的程序。在程序中執行一個需要長時間的執行的操作,為避免卡住UI主線程,我們會用到異步(future),可以使程序在等待一個耗時操作完成時繼續處理其他工作。
在進入正題之前,我們先了解一下 Dart 的消息循環機制:
- Dart 從兩個隊列執行任務:Event事件隊列 和 Microtask微任務隊列
- 事件循環會優先處理微任務隊列,microtask清空之后才將 event事件隊列中的下一個項目出隊并處理
- 事件隊列具有來自Dart(Future,Timer,Isolate Message等)和系統(用戶輸入,I/O等)
- 微任務隊列目前僅包含來自Dart,當然我們也可以自己往微隊列中插入任務
什么是 Future
Future 是什么?這里我們用小篇幅簡單描述一下。future是一個異步的執行操作,可以在不阻塞代碼的情況下實現耗時功能。
main() { Future(() { print('我是一個耗時操作'); }).then((value){ print('future 結束了'); }); print('main'); }
?//打印結果
main
我是一個耗時操作
future 結束了
在項目中,我們使用 Future
、Async
、await
相互組合實現異步編碼。
Future 操作具備'原子性'嗎
上面的篇幅我們說過,future 創建后會被直接加入到事件隊列依次執行。那么在上一個 future 在沒有標識完成前,下一個 future 可以被執行嗎?
小編寫了幾個樣例來做實驗:
實驗寫法一:
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); //耗時運算 print('一千年過去了'); return 'future1 結束了'; }); } static Future<String> future2() async { return Future(() async { print('開始 future2'); await TestTool.timeConsume(1000); //耗時運算 print('繼續 future2'); return 'future2 結束了'; }); } }
?//打印結果
開始 future1
一千年過去了
future1 結束了
開始 future2
繼續 future2
future2 結束了
實驗結果:
- 從打印結果上看,future任務沒有中斷,執行完當前任務后才可執行隊列中的下一個future
實驗寫法二:
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);//耗時運算 print('一千年過去了'); return 'future1 結束了'; } static Future<String> future2() async { print('開始 future2'); await TestTool.timeConsume(1000);//耗時運算 print('繼續 future2'); return 'future2 結束了'; } }
//打印結果
開始 future1
開始 future2
一千年過去了
future1 結束了
繼續 future2
future2 結束了
實驗結果:
- future2在future1沒有結束前就已經開始了任務。
- future2會在future1任務執行完成后響應結束,整個過程仍然保持了完成順序與加入事件隊列的順序一致性。
實驗寫法三:
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));//耗時運算 print('一千年過去了'); return 'future1 結束了'; } static Future<String> future2() async { print('開始 future2'); await TestTool.timeConsume(1000);//耗時運算 print('繼續 future2'); return 'future2 結束了'; } }
//打印結果
開始 future1
開始 future2
繼續 future2
future2 結束了
一千年過去了
future1 結束了
實驗結果:
- 從打印結果上看,future1開始后,future2直接開始任務,且future2任務完成后直接標識完成。
- future1 和 future2 的完成順序已經和加入事件隊列的順序無關了,只與內部耗時正相關。
附上耗時代碼:
abstract class TestTool { ///耗時操作 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; } }
論證結論
綜合上述三種寫法分析:
future方法體內部不屬于可靠的'原子性操作',不同的寫法有不同的差異性。 如果想將整個方法體內部作為不可拆分的執行單位。在外層使用Future進行包裹處理,如寫法一中Test1示例:
static Future<T> funcName() async { return Future(() async { ... 具體的方法體內容 ... return result; }); }
future在創建的同時,就會被加入到event事件隊列中。事件隊列是依次執行的,但每個future的完成順序與加入的順序不存在可靠的一致性。 如果在業務內想保持順序的一致性,可參考上述寫法,或使用 await
進行強制等待如:
main() async { await Test2.future1().then((value) => print(value)); Test2.future2().then((value) => print(value)); }
這樣寫,future2 就一定會在 future1 執行完成后才進入開始狀態。
原文鏈接:https://juejin.cn/post/7164289959359152159
相關推薦
- 2022-05-28 關于docker?compose安裝redis集群的問題(集群擴容、集群收縮)_docker
- 2022-10-24 python正則表達中的re庫常用方法總結_python
- 2022-08-18 Android顏色處理SweepGradient掃描及梯度渲染示例_Android
- 2022-03-10 Winform自定義控件在界面拖動、滾動鼠標時閃爍的解決方法_C#教程
- 2023-04-18 Python實現常見的4種坐標互相轉換_python
- 2022-09-06 golang根據生日計算星座和屬相實例_Golang
- 2023-01-26 如何在.Net?7中將Query綁定到數組詳解_實用技巧
- 2022-06-21 Git基礎之git與SVN版本控制優缺點區別分析_其它綜合
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支