Dart中的异步编程(Future、scheduleMicrot
2020-06-10 本文已影响0人
三国韩信
Dart是一门单线程的语言,Dart对异步操作对支持,可以使我们在编写Dart程序时可以异步的来执行耗时操作。这里的异步和多线程不是一个概念,在Dart中,异步但没有多线程,仍然是单线程。
Dart的事件循环(event loop)
在Dart中,实际上有两种队列:
- 事件队列(event queue),包含所有的外来事件:I/O、mouse events、drawing events、timers、isolate之间的信息传递。
- 微任务队列(microtask queue),表示一个短时间内就会完成的异步任务。它的优先级最高,高于event queue,只要队列中还有任务,就可以一直霸占着事件循环。microtask queue添加的任务主要是由 Dart内部产生。
因为 microtask queue 的优先级高于 event queue ,所以如果 microtask queue有太多的微任务, 那么就可能会霸占住当前的event loop。从而对event queue中的触摸、绘制等外部事件造成阻塞卡顿。
在每一次事件循环中,Dart总是先去第一个microtask queue中查询是否有可执行的任务,如果没有,才会处理后续的event queue的流程。
image.png
异步任务我们用的最多的还是优先级更低的 event queue。Dart为 event queue 的任务建立提供了一层封装,就是我们在Dart中经常用到的Future。
正常情况下,一个 Future 异步任务的执行是相对简单的:
- 声明一个 Future 时,Dart 会将异步任务的函数执行体放入event queue,然后立即返回,后续的代码继续同步执行。
- 当同步执行的代码执行完毕后,event queue会按照加入event queue的顺序(即声明顺序),依次取出事件,最后同步执行 Future 的函数体及后续的操作。
通过代码来看一下Future这个异步编程是啥样的(showCode)
void test1() {
String a = 'A';
print('最开始:$a');
for (int i = 0; i < 10000000000; i++) {
a = '网络请求';
}
print('结束:$a');
}
void test2() {
String a = 'A';
print('最开始a=:$a');
Future(() {
// 这里的耗时操作放到异步操作里去。 Future里的内容就是异步操作的
for (int i = 0; i < 10000000000; i++) {
a = '网络请求';
}
print('耗时操作最后a=:$a');
});
print('结束a=:$a');
}
void test3() async {
// async和await要配套使用
String a = 'A';
print('最开始a=$a');
await Future(() {
// 通过await去修饰,那么主线程会等Future的异步操作结束后再继续往下走。
for (int i = 0; i < 10000000000; i++) {
a = '网络请求';
}
});
print('结束a=$a');
}
void test4() {
String a = 'A';
print('最开始a=$a');
Future future = Future(() {
// Future通过返回一个Future对象可以来操作then,达到和test3一样的效果。
for (int i = 0; i < 1000000000; i++) {
a = '网络请求';
}
print('耗时操作里面的a=$a');
return a;
});
future.then((onValue) {
print('then里面的a=$a');
});
}
void test5() {
String a = 'A';
print('最开始a=$a');
Future(() {
// Future通过链式调用的方式,推荐用这种方式。把需要在耗时操作后面执行的内容放到then里面去。
// then里面的内容一样是异步。
for (int i = 0; i < 1000000000; i++) {
a = '网络请求';
}
print('耗时操作里面的a=$a');
return a;
}).then((onValue) {
print('then里面的a=$a');
});
}
void test6() {
// 多个Future存在的时候,顺序是怎样的呢?
print('主线程同步开始');
Future(() {
print('任务1开始');
return '任务1';
}).then((value) => print('$value结束了'));
Future(() {
print('任务2开始');
return '任务2';
}).then((value) => print('$value结束了'));
Future(() {
print('任务3开始');
return '任务3';
}).then((value) => print('$value结束了'));
Future(() {
print('任务4开始');
return '任务4';
}).then((value) => print('$value结束了'));
Future(() {
print('任务5开始');
return '任务5';
}).then((value) => print('$value结束了'));
print('主线程同步结束');
}
void test61() {
// Future 数组 多个Future还可以用数组的形式来表达
Future.wait([
Future(() {
return '任务1';
}),
Future(() {
return '任务2';
}),
]).then((value) => print('任务执行结果为:${value[0]} 以及 ${value[1]}'));
// 此时then里的内容会等Future数组里的2个异步任务都执行完毕了再执行。
}
void test7() {
// 多个Future中还存在microtask(微任务)的时候,执行顺序又是如何
print('主线程同步开始');
/*
1、Future的异步事件是按Future声明的顺序放入的event loop里的,then里的异步操作是放到微任务microtask loop 里面的。
2、microtask loop队列里的异步事件的执行优先级比event loop异步队列里的优先级高
3、每个loop time的时候都会先去microtask loop队列里看看当前是否有microtask未执行,有的话,优先执行microtask。
*/
Future(() {
print('任务1开始');
scheduleMicrotask(() {
// 这个microtask比then要晚执行,是因为他比then要晚放到microtask队列里。 then是在当前的Future申明的时候就放进去了,而这个
// microtast 是Future执行的时候才放进去的,所以比then要晚。 注 then虽然可以理解是放到microtask队列里,但是它只有当前的Future执行完才会执行的。
print('任务1里的微任务1开始');
});
return '任务1';
}).then((value) => print('$value结束了'));
Future(() {
print('任务2开始');
scheduleMicrotask(() {
print('任务2里的微任务1开始');
});
return '任务2';
}).then((value) => print('$value结束了'));
Future(() {
print('任务3开始');
scheduleMicrotask(() {
print('任务3里的微任务1开始');
});
return '任务3';
}).then((value) => print('$value结束了'));
Future(() {
print('任务4开始');
scheduleMicrotask(() {
print('任务4里的微任务1开始');
});
return '任务4';
}).then((value) => print('$value结束了'));
Future(() {
print('任务5开始');
scheduleMicrotask(() {
print('任务5里的微任务1开始');
});
return '任务5';
}).then((value) => print('$value结束了'));
scheduleMicrotask(() {
print('这是微任务');
});
print('主线程同步结束');
}
void test8() {
// 猜猜看,执行顺序是啥。。。
Future x1 = Future(() => null);
Future x = Future(() => print('1'));
Future(() => print('2'));
scheduleMicrotask(() => print('3'));
x.then((value) => print('4'));
print('5');
x1.then((value) => print('6'));
// 答案是:5、3、6、1、4、2
}
void test9() {
// 猜猜看,执行顺序是啥。。。
Future x1 = Future(() => null);
x1.then((value) {
print('6');
scheduleMicrotask(() => print('7'));
}).then((value) => print('8'));
Future x = Future(() => print('1'));
Future(() => print('2'));
scheduleMicrotask(() => print('3'));
x.then((value) => print('4'));
print('5');
// 答案是:5、3、6、8、7 、1、4、2
}
void test10() {
//flutter的多线程 Isolate 执行顺序是无序的,且变量和外部的变量是隔离的。即便同名变量也是2个不同的变量
// 好处是不用担心多线程访问对资源的抢夺。
Isolate.spawn(fun11, 100);
Isolate.spawn(fun12, 200);
Isolate.spawn(fun11, 100);
Isolate.spawn(fun12, 200);
Isolate.spawn(fun11, 100);
Isolate.spawn(fun12, 200);
Isolate.spawn(fun11, 100);
Isolate.spawn(fun12, 200);
Isolate.spawn(fun11, 100);
Isolate.spawn(fun12, 200);
Isolate.spawn(fun13, {'name': '112'});
}
void fun11(int count) {
print('fun11--$count');
}
void fun13(Map count) {
print('fun11--$count');
}
void fun12(int count) {
print('fun12--$count');
}
void test12() {
print('函数主线程开始');
// compute是一个多线程。
compute(fun14, {'name': '112'}).then((value) => print(value));
print('函数主线程结束');
}
Map fun14(Map count) {
print('fun11--$count');
return count;
}