小知识,大挑战!本文正在参与“ 程序员必备小知识”创作活动。
介绍
众所周知,dart是单线程模型,没有Android中多线程的概念,但并不是说不存在异步,程序中异步操作是一定存在的,所以dart中提供了一种类似线程概念的东西-isolate,与线程不同的是,多个isolate之间是隔离的,内存是不共享的,所以是不存在并发问题的,也有人称之为isolate是像进程一样的线程。Android和Dart的虚拟机模型如下:
isolate创建
在dart中,程序在启动时,执行main方法后会默认创建一个主isolate,那么我们该如何创建一个子isolate去执行异步任务呢? isolate中自己提供了静态方法spawn来创建一个isolate,该方法中需要传入两个必传参数:
- entryPoint:指定要在生成的isolate中调用的初始函数。
- message: entryPoint函数中要接收的参数,通常用于传递sendPort来进行isolate通信。
void main(){
Isolate.spawn(entryPoint, "message");
}
void entryPoint(String message){
print(message);
}
验证内存隔离
创建了子isolate之后,我们可以验证一下不同isolate之间是内存隔离的吗?如下声明一个全局num,在main进行赋值操作,分别在main isolate和子isolate中打印num的值,通过控制台日志可以发现子isolate中是获取不到num的值的。
int num;
void main(){
num = 1;
Isolate.spawn(entryPoint, "message");
print("main num $num");
}
void entryPoint(String message){
print("entryPoint num $num");
}
isolate通信
像Android中我们使用Handler等进行线程通信,那么看下dart中isolate是如何发送接收数据的。
ReceivePort receivePort = ReceivePort();
receivePort.listen((message) {
print(message);
});
receivePort.sendPort.send("这是通信消息");
receivePort.sendPort.send(1);
通过创建一个接收器ReceivePort,使用它的发送器sendPort发送消息,并通过receivePort的listen方法监听来接收所发送的消息。需要注意的是,send中发送的数据是不限制数据类型的。
前面说了spawn中的message参数通常是传入main isolate的sendport,从而来进行不同isolate间的通信,也就是可以理解为,我把我的发送器给你,并准备一个接收器接收发送器发送的消息,当你需要发送消息的时候通过发送器把消息发送给我就可以了:
void main(){
ReceivePort receivePort = ReceivePort();
Isolate.spawn(entryPoint, receivePort.sendPort);
receivePort.listen((message) {
print(message);
});
}
void entryPoint(SendPort sendPort){
// 模拟耗时操作
Future.delayed(Duration(seconds: 2),(){
sendPort.send("子isolate里面给你发的消息");
});
}
如图所示,main isolate在2s后接收到了来自子isolate中发送的消息。
双向通信
上边说我们可以把main isolate的发送器传递给子isolate来实现通信,那么同样也可以把子isolate的发送器传递给main isolate,这样就可以实现双向通信。由于send方法是不限制发送的数据类型的,因此可以利用此特性当接收到main isolate数据后首先把子isolate的发送器发送过去,之后在进行其他通信数据的发送:
void main(){
ReceivePort receivePort = ReceivePort();
Isolate.spawn(entryPoint, receivePort.sendPort);
receivePort.listen((message) {
if(message is SendPort){
print("main接收到子isolate的发送器了");
Future.delayed(Duration(seconds: 1),(){
message.send("main给子isolate发送的消息");
});
}else{
print(message);
}
});
}
void entryPoint(SendPort sendPort){
ReceivePort receivePort = ReceivePort();
receivePort.listen((message) {
print("子isolate接收到main的消息了:$message");
});
sendPort.send(receivePort.sendPort);
// 模拟耗时操作
Future.delayed(Duration(seconds: 2),(){
sendPort.send("子isolate里面给main发的消息");
});
}
如下所示,main中首先接收到了来自子isolate发送过来的发送器,然后用此发送器给子isolate发送了消息,从而实现了两端双向通信的场景。
需要格外注意的是,当不再使用接收器时,一定要及时调用receivePort.close()
isolate的状态方法
暂停:
isolate.pause(isolate.pauseCapability);
恢复:
isolate.resume(isolate.pauseCapability);
结束:
isolate.kill(priority: Isolate.immediate);