Dart - Isolate 并发
在Dart中实现并发可以用Isolate,它是类似于线程(thread)但不共享内存的独立运行的worker,是一个独立的Dart程序执行环境。其实默认环境就是一个main isolate。
在Dart语言中,所有的Dart代码都运行在某个isolate中,代码只能使用所属isolate的类和值。不同的isolate可以通过port发送message进行交流。(首字母大写的Isolate代表Isolate对象,小写的isolate代表一个独立的Dart代码执行环境)
一个Isolate对象就是一个isolate(执行环境)的引用,通常不是当前代码所在的isolate,也就是说,当你使用Isolate对象时,你的目的应该是控制其他isolate,而不是当前的isolate。
当你要spawn(产生)一个新isolate时,如果操作成功,当前isolate会接收到一个代表新isolate的Isolate对象。
isolate在它自己的事件循环(event loop)中执行代码,每个事件都可以在该isolate的微任务队列(microtask queue)中执行更小的任务。(点击查看更多关于事件循环与微任务队列的资料)
Isolate对象允许其他isolate控制、监听它所代表的isolate的事件循环,例如当这个isolate发生未捕获错误时,可以暂停(pause)此isolate或获取(addErrorListener)错误信息。
controlPort识别并授予对isolate控制的权限,pauseCapability和terminateCapability会对某些控制操作进行权限保护。例如,暂停(pause)一个无pauseCapability的Isolate对象是不生效的。
由spawn操作创建的Isolate对象具有控制接口(control port)和控制该对象的能力(capability)。当然, 用Isolate.Isolate构造方法创建的Isolate对象可以不必带有这些能力。
Isolate对象不能用SendPort发送给另一个Isolate对象,但是控制接口(control port)和能力(capability)是可以发送的,并且可以在另一个Isolate对象中用发送来的接口与能力创建一个新的Isolate对象。
Spawn<T>方法
spawn<T>( void entryPoint(T message), T message, { bool paused: false, bool errorsAreFatal, SendPort onExit, SendPort onError } ) → Future<Isolate>
创建一个与当前isolate共享代码的isolate(并不是共享内存,仅代码)。
entryPoint参数指定了调用产生的isolate时的初始函数。入口函数(entry-point function)在新isolate中以message作为唯一参数被调用。(可以想到,默认的isolate以main()函数作为入口)
这个函数必须是可以以单一参数调用的全局函数或静态方法,也就是说,它应该是接收至少一个位置参数并且最多一个必要位置参数的编译时函数常量值。只要它能用一个参数来调用,它可以接收任意数量的可选参数。它不能是函数表达式或实例方法。
初始化消息(message)通常包含一个SendPort,以便生产者与被产者互相交流。
如果paused参数赋值为true,那么这个isolate启动时就是entryPoint方法调用前的暂停状态,就像初始化时就调用了isolate.pause(isolate.pauseCapability)一样。要恢复运行,可以调用isolate.resume(isolate.pauseCapability)。
如果errorsAreFatal、 onExit 和/或 onError 参数被赋值,就相当于在isolate启动前,setErrorsFatal, addOnExitListener 和/或 addErrorListener 分别以相应参数调用。
如果忽略errorsAreFatal参数,平台会以默认行为或者继承自当前isolate的行为来处理错误。
你也可以对返回的isolate调用setErrorsFatal、addOnExitListener 和 addErrorListene等方法,但是除非isolate以pause状态启动,它在这些方法调用前可能已经执行完毕了。
示例
import 'dart:async'; import 'dart:isolate'; main() async { var receivePort = new ReceivePort(); await Isolate.spawn(echo, receivePort.sendPort); // 'echo'发送的第一个message,是它的SendPort var sendPort = await receivePort.first; var msg = await sendReceive(sendPort, "foo"); print('received $msg'); msg = await sendReceive(sendPort, "bar"); print('received $msg'); } /// 新isolate的入口函数 echo(SendPort sendPort) async { // 实例化一个ReceivePort 以接收消息 var port = new ReceivePort(); // 把它的sendPort发送给宿主isolate,以便宿主可以给它发送消息 sendPort.send(port.sendPort); // 监听消息 await for (var msg in port) { var data = msg[0]; SendPort replyTo = msg[1]; replyTo.send(data); if (data == "bar") port.close(); } } /// 对某个port发送消息,并接收结果 Future sendReceive(SendPort port, msg) { ReceivePort response = new ReceivePort(); port.send([msg, response.sendPort]); return response.first; }
注意
目前无法在新isolate中调用平台方法(platform channel method),调用时应用会闪退且没有报错信息。
详情请看 Unable to call a platform channel method from a another isolate #13937
Flutter中文文档