Dart是如何完成耗时操作的?
- Dart完成耗时操作的原理是:
基于单线程 + 事件循环(Event Loop)
来完成耗时操作,且这些耗时操作都是非阻塞式调用
- 另外:你要知道
Dart是单线程的
,那他是如何搞定异步的呢?(下面会分析)
概念补充
- 阻塞式调用和非阻塞式调用
- 阻塞式调用:调用结果返回之前,当前线程会
被挂起
,调用线程只有在得到调用结果之后才会继续执行
- 非阻塞式调用:调用执行之后,当前线程
继续执行
,只需要过一段时间来检查一下有没有结果返回即可
- 事件循环
- 将需要处理的一系列事件(包括点击事件、IO事件、网络事件)放在一个
事件队列(Event Queue)
中
- 不断的从
事件队列(Event Queue)
中取出事件,并执行,直到事件队列中所有事件都被执行了为止
Dart是如何搞定异步的?
- Dart中的异步操作主要使用
Future
以及async、await
,即:实现非阻塞式调用
Future
import 'dart:io';
main(List<String> args) {
print("main start");
// 模拟一个网络请求
var future = getNetworkData();
// 通过.then(成功回调函数)的方式来监听Future内部执行完成时获取到的结果
future.then((String value) {
print(value);
})
// 通过.catchError(失败或异常回调函数)的方式来监听Future内部执行失败或者出现异常时的错误信息
.catchError((err) {
print(err);
})
// 这里是一定会执行的
.whenComplete(() {
print("代码执行完毕");
});
print("main end");
}
Future<String> getNetworkData() {
return Future<String>(() {// 将耗时的操作包裹到Future的回调函数中
// 模拟网络请求
sleep(Duration(seconds: 3));
// 模拟有返回结果, 那么就执行Future对应的then的回调
return "result";
// 模拟有错误信息, 需要在Future回调中抛出一个异常
// throw Exception("我是错误信息");
});
}
import 'dart:io';
main(List<String> args) {
print("main start");
// Future的链式调用
Future(() {
// 1.发送第一次请求
sleep(Duration(seconds: 3));
return "第一次的结果";
}).then((res) {
print(res);
// 2.发送的第二次请求
sleep(Duration(seconds: 2));
return "第二次的结果";
// throw Exception("第二次异常");
}).then((res) {
print(res);
// 3.发送的第三次请求
sleep(Duration(seconds: 1));
return "第三次的结果";
}).then((res) {
print(res);
}).catchError((err) {
// 捕获异常
print(err);
});
print("main end");
}
main(List<String> args) {
/** 打印结果
* futureValueMethod start
* futureValueMethod end
* 哈哈哈
*
* 为什么“哈哈哈”是在最后打印的呢???
* 因为Future中的then会作为新的任务会加入到事件队列中(Event Queue),加入之后你肯定需要排队执行了
*/
// futureValueMethod();
/** 打印结果
* futureErrorMethod start
* futureErrorMethod end
* 错误信息
*
* 为什么“错误信息”是在最后打印的呢???
* 答案如上所述
*/
// futureErrorMethod();
/** 打印结果
* futureDelayedMethod start
* futureDelayedMethod end
* result
*/
futureDelayedMethod();
}
void futureValueMethod() {
print("futureValueMethod start");
// 直接获取一个完成的Future,该Future会直接调用then的回调函数
Future.value("哈哈哈").then((res) {
print(res);
});
print("futureValueMethod end");
}
void futureErrorMethod() {
print("futureErrorMethod start");
// 直接获取一个完成的Future,但是一个发生异常的Future,该Future会直接调用catchError的回调函数
Future.error("错误信息").catchError((err) {
print(err);
});
print("futureErrorMethod end");
}
void futureDelayedMethod() {
print("futureDelayedMethod start");
// 延迟一定时间后执行回调函数,执行完回调函数后会执行then的回调
Future<String>.delayed(Duration(seconds: 3), () {
return "result";
}).then((res) {
print(res);
});
print("futureDelayedMethod end");
}
async、await
- 通过这两个关键字可以让我们用
同步的代码格式
,去实现异步的调用过程
- 通常一个
async
的函数会返回一个Future
- 通过
async、await
完成网络请求
import 'dart:io';
main(List<String> args) {
print("main start");
var result = getNetworkData().then((res) {
print(res);
});
print(result);
print("main end");
}
/**
* 解决两个问题:
* 1.await必须在async函数中才能使用
* 2.async函数返回的结果必须是一个Future
* 3.返回值会默认被包装在一个Future中
*/
Future getNetworkData() async {
await sleep(Duration(seconds: 3));
return "Hello World";
}
import 'dart:io';
main(List<String> args) {
print("main start");
/** 打印结果
* main start
* main end
* argument1
* argument12
* argument123
*/
getData().then((res) {
print(res);
}).catchError((err) {
print(err);
});
print("main end");
}
Future getData() async {
// 调用第1次网络请求
var res1 = await getNetworkData("argument1");
print(res1);
// 调用第2次网络请求
var res2 = await getNetworkData(res1+"2");
print(res2);
// 调用第3次网络请求
var res3 = await getNetworkData(res2+"3");
return res3;
}
Future getNetworkData(String arg) {
return Future(() {
sleep(Duration(seconds: 3));
return arg;
});
}
Isolate
- Dart是单线程的,这个线程有自己可以访问的
内存空间
以及事件循环
,我们可以将这个空间系统
称之为是一个Isolate
- 在 Isolate 中,
资源隔离
做得非常好,每个 Isolate 都有自己的 Event Loop
与 Queue
- Isolate 之间
不共享
任何资源,只能依靠消息机制
通信,因此也就没有资源抢占
问题
- 如果只有一个Isolate,那么意味着我们只能永远利用一个线程,这对于多核CPU来说,是一种资源的浪费
- 在开发中,我们有非常多耗时的计算,完全可以自己创建Isolate,在独立的Isolate中完成想要的计算操作
- 创建Isolate
import 'dart:isolate';
main(List<String> args) {
print("main start");
// 开启一个新的Isolate
Isolate.spawn(calc, 100);
print("main end");
}
void calc(int count) {
var total = 0;
for (var i = 0; i < count; i++) {
total += i;
}
print(total);
}
import 'dart:isolate';
main(List<String> args) async {
print("main start");
// 1.创建管道
ReceivePort receivePort = ReceivePort();
// 2.创建新的Isolate
Isolate isolate = await Isolate.spawn<SendPort>(foo, receivePort.sendPort);
// 3.监听管道消息
receivePort.listen((message) {
print("message: $message");
// 不再使用时,我们会关闭管道
receivePort.close();
// 需要将isolate杀死
isolate?.kill(priority: Isolate.immediate);
});
print("main end");
}
void foo(SendPort send) {
return send.send("Hello Flutter");
}
-
Flutter
提供了支持并发计算的compute函数,它内部封装了Isolate的创建和双向通信,注意:不是dart的API,而是Flutter的API,所以只有在Flutter项目中才能运行
// 此代码必须在Flutter项目中才能运行
main(List<String> args) async {
int result = await compute(powerNum, 5);
print(result);
}
int powerNum(int num) {
return num * num;
}
网友评论