「这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战」
Future异步
在上面网络请求的时候用到了Future
,那么这个到底是什么?Fluture
是主线程当中的异步代码
- 下面打印的顺序是什么:
void main() {
testFuture();
print('A');
}
void testFuture() async {
Future(() {
print('C');
});
print('B');
}
复制代码
- 加入
await
之后打印的顺序是什么?
void main() {
testFuture();
print('A');
}
void testFuture() async {
await Future(() {
print('C');
}).then((value) => print('D'));
print('B');
}
复制代码
经过测试发现使用
Future
修饰的代码块会异步执行,不会卡住当前的线程。如果希望在这个异步任务执行完成之后再操作,需要在Future前面加上一个await。
- 多个
Future
并行的时候的打印顺序:
void main() {
testFuture();
print('A');
}
void testFuture() async {
Future(() {
return '任务1';
}).then((value) => print('$value 执行结束'));
Future(() {
return '任务2';
}).then((value) => print('$value 执行结束'));
Future(() {
return '任务3';
}).then((value) => print('$value 执行结束'));
Future(() {
return '任务4';
}).then((value) => print('$value 执行结束'));
print('任务添加完毕');
}
复制代码
调整顺序或者是让其中的一个任务加入睡眠等多项测试之后,发现多个
Future
并行发现这个执行的顺序就是添加的顺序。
- 有依赖关系的
Future
打印顺序:
void testFuture() async {
Future(() {
return '任务1';
}).then((value) {
print('$value结束');
return '$value任务2';
}).then((value) {
print('$value结束');
return '$value任务3';
}).then((value) {
print('$value结束');
return '$value任务4';
});
}
复制代码
- 多个
Future
执行完成之后再操作:
void testFuture() async {
Future.wait([
Future(() {
return '任务1';
}),
Future(() {
return '任务2';
}),
Future(() {
return '任务3';
}),
Future(() {
return '任务4';
}),
]).then((value) => print('$value')); // wait里面的执行顺序也是添加的顺序
}
复制代码
scheduleMicrotask
可以插队到Future
任务前面
void testFuture() async {
Future.wait([
Future(() {
return '任务1';
}),
Future(() {
return '任务2';
}),
Future(() {
return '任务3';
}),
Future(() {
return '任务4';
}),
]).then((value) => print('$value'));
scheduleMicrotask(() {
print('scheduleMicrotask');
});
}
复制代码
Dart
中就只有两种队列:一种是事件队列,一种是微任务队列,微任务队列的优先级始终高于事件队列。
下图为官方图:
- 下列打印的顺序是什么?
void testFuture() async {
Future x = Future(() => print('A'));
Future(() => print('B'));
scheduleMicrotask(() {
print('C');
});
x.then((value) => print('D'));
print('E');
}
复制代码
首先肯定是主线程的E
,然后是微任务的C
,剩下的两个Future
按照添加的顺序执行,首先执行A和D最后是B
Fluture
中嵌套微任务的执行顺序:
void testFuture() async {
Future(() => print('A')).then((value) {
scheduleMicrotask(() {
print('D');
});
}).then((value) => print('F'));
Future(() => print('B'));
scheduleMicrotask(() {
print('C');
});
print('E');
}
复制代码
这里可以这么理解:then
后面的代码可以理解为丢到了微任务队列去执行。
补充:使用Flutter的时候尽量使用链式调用,保证在最后调用.catchError
来捕获异常
getData() async {
print('开始了');
await Future(() {
for (int i = 0; i < 100; i++) {}
return '循环结束';
})
.then((value) => print('$value'))
.whenComplete(() => print('完成了'))
.catchError((e) => print(e.toString()));
print('await之后的代码');
}
复制代码
Dart中的多线程
Dart当中的Isolate
更像一个进程,有独立的内存空间。意味着每个进程之间的数据是独立的,不存在抢夺空间的情况,所以不需要锁的概念。
void main() {
IsolateDemo();
}
void IsolateDemo() {
print('1');
Isolate.spawn(func, 3);
Isolate.spawn(func, 4);
Isolate.spawn(func, 5);
Isolate.spawn(func, 6);
Isolate.spawn(func, 7);
Isolate.spawn(func, 8);
Isolate.spawn(func, 9);
sleep(Duration(seconds: 3));
print('2');
}
复制代码
上面说了不存在同一块内存的问题,我们也来验证一下,在下面的代码中,我在
Isolate
中修改了a的值,那么最后打印的a=?
int a = 100;
void IsolateDemo() {
print('1');
Isolate.spawn(func, 3);
Isolate.spawn(func, 4);
Isolate.spawn(func, 5);
Isolate.spawn(func, 6);
Isolate.spawn(func, 7);
Isolate.spawn(func, 8);
Isolate.spawn(func, 9);
sleep(Duration(seconds: 3));
print('2');
print('a = $a');
}
func(int count) {
print('$count');
a = count;
}
复制代码
经验证,最后a还是等于100.也就是说在
Isolate
中的修改并没有效果。
ReceivePort & Isolate
void IsolateDemo() {
print('1');
ReceivePort port = ReceivePort();
Isolate.spawn(func, port.sendPort);
port.listen((message) {
print('message=$message');
});
sleep(Duration(seconds: 3));
print('2');
}
func(SendPort port) {
port.send(10);
}
复制代码
上面的代码还是有一点需要完善的地方:此时注意需要手动的关闭端口和销毁Isolate
void IsolateDemo() async {
print('1');
ReceivePort port = ReceivePort();
Isolate iso = await Isolate.spawn(func, port.sendPort);
port.listen((message) {
print('message=$message');
port.close();
iso.kill();
});
sleep(Duration(seconds: 3));
print('2');
}
复制代码
compute
用法跟Isolat
e差不多,是在Isolate
上的进一步包装。compute
不需要手动kill
void main() {
Comouterdemo();
}
void Comouterdemo() {
print('1');
compute(func1, 10);
sleep(Duration(seconds: 3));
print('2');
}
func1(int num) {
print('$num');
}
复制代码
搭配await
异步使用
void main() {
Comouterdemo();
}
void Comouterdemo() async {
print('1');
int result = await compute(func1, 10);
sleep(Duration(seconds: 3));
print('result=$result');
print('2');
}
int func1(int num) {
print('$num');
return num;
}
复制代码
一些小知识
- 关于import, as关键字就是给库起别名,目的是防止类名、方法名冲突
import 'package:http/http.dart' as http;
- 导入库,默认是整个文件都会导入,如果需要指定的话有两个关键字。
show
:执行需要导入的内容;hide:
需要隐藏的内容 pubspec.yaml
中publish_to
:指定发布到哪里去,默认的都是到pub.dev
里面去pubspec.yaml
中version
: 当前项目的版本号pubspec.yaml
中 Dart的版本environment:sdk: ">=2.12.0 <3.0.0"
pubspec.yaml
中dev_dependencies
: 开发环境依赖的版本打包的时候不会有这些pubspec.yaml
中dependencies
: 第三方库导入位置。dio:^4.0.1
大版本不变的区间写法,相当于>=4.0.1 <5.0.0
;dio:4.0.1
指定4.0.1版本;dio:any
任意版本