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

