转载请联系: 微信号: michaelzhoujay数组
原文请访问个人博客微信
本文主要介绍Flutter中Event Loop以及如何在Flutter中作parallel processing.网络
First things first, everyone needs to bear in mind that Dart is Single Thread and Flutter relies on Dart.async
IMPORTANT Dart executes one operation at a time, one after the other meaning that as long as one operation is executing, it cannot be interrupted by any other Dart code.ide
跟AndroidVM相似,当你启动一个Flutter的App,那么就会系统就会启动一个DartVM Flutter中的Dart VM启动后,那么一个新的Thread就会被建立,而且只会有一个线程,它运行在本身的Isolate中。oop
当这个Thread被建立后,DartVM会自动作如下3件事情:学习
Event Loop就像一个 infinite loop,被内部时钟来调谐,每个tick,若是没有其余Dart Code在执行,就会作以下的事情(伪代码):fetch
void eventLoop(){
while (microTaskQueue.isNotEmpty){
fetchFirstMicroTaskFromQueue();
executeThisMicroTask();
return;
}
if (eventQueue.isNotEmpty){
fetchFirstEventFromQueue();
executeThisEventRelatedCode();
}
}
复制代码
MicroTask Queue是为了很是短暂的asynchronously的内部操做来设计的。在其余Dart代码运行完毕后,且在移交给Event Queue前。ui
举个例子,咱们常常须要在close一个resource之后,dispose掉一些handle,下面的这个例子里,scheduleMicroTask 能够用来作 dispose 的事情:this
MyResource myResource;
...
void closeAndRelease() {
scheduleMicroTask(_dispose);
_close();
}
void _close(){
// The code to be run synchronously
// to close the resource
...
}
void _dispose(){
// The code which has to be run
// right after the _close()
// has completed
}
复制代码
这里,虽然scheduleMicroTask(_dispose)
语句在_close()
语句以前,可是因为上面说到的,“其余Dart代码执行完毕后”,因此_close()
会先执行,而后执行 Event loop 的 microTask。
即便你已经知道 microTask 的执行时机,并且还学习了用scheduleMicroTask
来使用 microTask,可是 microTask 也不是你经常使用的东西。就 Flutter 自己来讲,整个 source code只引用了 scheduleMicroTask()
7次。
Event Queue 主要用来处理当某些事件发生后,调用哪些操做,这些事件分为:
事实上,每当外部事件发生时,要执行的代码都是在 Event Queue里找到的。 只要当没有 MicroTask 须要run了,那么 Event Queue 就会从第一个事件开始处理
当你建立了一个future的实例,其实是作了如下几件事情:
incomplete
Future和其余Event同样,会在EventQueue里被执行。 如下的例子用来讲明Future和上面的Event执行过程同样
void main(){
print('Before the Future');
Future((){
print('Running the Future');
}).then((_){
print('Future is complete');
});
print('After the Future');
}
复制代码
执行后,会获得以下输出:
Before the Future
After the Future
Running the Future
Future is complete
复制代码
咱们来分步骤解释一下代码是如何执行的:
A Future is NOT executed in parallel but following the regular sequence of events, handled by the Event Loop
若是在任何一个方法的声明部分加上 async
后缀,那么你实际上在向dart代表:
每一个线程有本身的Isolate,你能够用Isolate.spawn
或者是 compute
来建立一个 Isolate 每一个Isolate都有本身的Data,和Event loop Isolate之间经过消息来进行沟通
Isolate.spawn(
aFunctionToRun,
{'data' : 'Here is some data.'},
);
复制代码
compute(
(paramas) {
/* do something */
},
{'data' : 'Here is some data.'},
);
复制代码
当你在一个Isolate中,建立了一个新的Isolate,而后要和新的Isolate进行沟通,那么就须要SendPort
和ReceivePort
。 为了能沟通,两个Isolate必需要互相知晓对方的port:
SendPort
来收/发消息,官方起的名字真的是有些让人困惑。spawn
方法传递一个 ReceivePort
的实例,后续会用这个port来收/发消息,同时也会经过这个port把本地 Isolate的sendport返回找了一个例子,感觉一下
//
// The port of the new isolate
// this port will be used to further
// send messages to that isolate
//
SendPort newIsolateSendPort;
//
// Instance of the new Isolate
//
Isolate newIsolate;
//
// Method that launches a new isolate
// and proceeds with the initial
// hand-shaking
//
void callerCreateIsolate() async {
//
// Local and temporary ReceivePort to retrieve
// the new isolate's SendPort
//
ReceivePort receivePort = ReceivePort();
//
// Instantiate the new isolate
//
newIsolate = await Isolate.spawn(
callbackFunction,
receivePort.sendPort,
);
//
// Retrieve the port to be used for further
// communication
//
newIsolateSendPort = await receivePort.first;
}
//
// The entry point of the new isolate
//
static void callbackFunction(SendPort callerSendPort){
//
// Instantiate a SendPort to receive message
// from the caller
//
ReceivePort newIsolateReceivePort = ReceivePort();
//
// Provide the caller with the reference of THIS isolate's SendPort
//
callerSendPort.send(newIsolateReceivePort.sendPort);
//
// Further processing
//
}
复制代码
两个 Isolate 都有了各自的port,那么它们就能够开始互发消息了:
本地Isolate向新Isolate发消息并回收结果:
Future<String> sendReceive(String messageToBeSent) async {
//
// We create a temporary port to receive the answer
//
ReceivePort port = ReceivePort();
//
// We send the message to the Isolate, and also
// tell the isolate which port to use to provide
// any answer
//
newIsolateSendPort.send(
CrossIsolatesMessage<String>(
sender: port.sendPort,
message: messageToBeSent,
)
);
//
// Wait for the answer and return it
//
return port.first;
}
复制代码
本地Isolate被动收消息,还记得上面的spawn
方法吗,第一个参数是 callbackFunction
这个方法就是用来收结果的:
//
// Extension of the callback function to process incoming messages
//
static void callbackFunction(SendPort callerSendPort){
//
// Instantiate a SendPort to receive message
// from the caller
//
ReceivePort newIsolateReceivePort = ReceivePort();
//
// Provide the caller with the reference of THIS isolate's SendPort
//
callerSendPort.send(newIsolateReceivePort.sendPort);
//
// Isolate main routine that listens to incoming messages,
// processes it and provides an answer
//
newIsolateReceivePort.listen((dynamic message){
CrossIsolatesMessage incomingMessage = message as CrossIsolatesMessage;
//
// Process the message
//
String newMessage = "complemented string " + incomingMessage.message;
//
// Sends the outcome of the processing
//
incomingMessage.sender.send(newMessage);
});
}
//
// Helper class
//
class CrossIsolatesMessage<T> {
final SendPort sender;
final T message;
CrossIsolatesMessage({
@required this.sender,
this.message,
});
}
复制代码
若是建立的Isolate再也不使用,那么最好是能将其release掉:
void dispose(){
newIsolate?.kill(priority: Isolate.immediate);
newIsolate = null;
}
复制代码
实际上Isolate之间的沟通是经过 “Single-Listener” Streams 来实现的。
上面说过建立 Isolate的方式,其中 compute 适合于建立之后执行任务,并且完成任务后你不但愿有任何沟通。 compute是个function:
如何挑选呢?
通常来讲: