isolate两三事

1.1. 第一步:创建并握手

如前所述,Isolate 不共享任何内存并通过消息进行交互,因此,我们需要找到一种方法在「调用者」与新的 isolate 之间建立通信。

每个 Isolate 都暴露了一个将消息传递给 Isolate 的被称为「SendPort」的端口。(个人觉得该名字有一些误导,因为它是一个接收/监听的端口,但这毕竟是官方名称)。

这意味着「调用者」和「新的 isolate」需要互相知道彼此的端口才能进行通信。这个握手的过程如下所示:

 

 

// 新的 isolate 端口
// 该端口将在未来使用
// 用来给 isolate 发送消息
//
SendPort newIsolateSendPort;
 
//
// 新 Isolate 实例
//
Isolate newIsolate;
 
//
// 启动一个新的 isolate
// 然后开始第一次握手
//
//
void callerCreateIsolate() async {
    //
    // 本地临时 ReceivePort
    // 用于检索新的 isolate 的 SendPort
    //
    ReceivePort receivePort = ReceivePort();
 
    //
    // 初始化新的 isolate
    //
    newIsolate = await Isolate.spawn(
        callbackFunction,
        receivePort.sendPort,
    );
 
    //
    // 检索要用于进一步通信的端口
    //
    //
    newIsolateSendPort = await receivePort.first;
}
 
//
// 新 isolate 的入口
//
static void callbackFunction(SendPort callerSendPort){
    //
    // 一个 SendPort 实例,用来接收来自调用者的消息
    //
    //
    ReceivePort newIsolateReceivePort = ReceivePort();
 
    //
    // 向调用者提供此 isolate 的 SendPort 引用
    //
    callerSendPort.send(newIsolateReceivePort.sendPort);
 
    //
    // 进一步流程
    //
}

  

 

1.2. 第二步:向 Isolate 提交消息

现在我们有了向 Isolate 发送消息的端口,让我们看看如何做到这一点:

//
// 向新 isolate 发送消息并接收回复的方法
//
//
// 在该例中,我将使用字符串进行通信操作
// (发送和接收的数据)
//
Future<String> sendReceive(String messageToBeSent) async {
    //
    // 创建一个临时端口来接收回复
    //
    ReceivePort port = ReceivePort();
 
    //
    // 发送消息到 Isolate,并且
    // 通知该 isolate 哪个端口是用来提供
    // 回复的
    //
    newIsolateSendPort.send(
        CrossIsolatesMessage<String>(
            sender: port.sendPort,
            message: messageToBeSent,
        )
    );
 
    //
    // 等待回复并返回
    //
    return port.first;
}
 
//
// 扩展回调函数来处理接输入报文
//
static void callbackFunction(SendPort callerSendPort){
    //
    // 初始化一个 SendPort 来接收来自调用者的消息
    //
    //
    ReceivePort newIsolateReceivePort = ReceivePort();
 
    //
    // 向调用者提供该 isolate 的 SendPort 引用
    //
    callerSendPort.send(newIsolateReceivePort.sendPort);
 
    //
    // 监听输入报文、处理并提供回复的
    // Isolate 主程序
    //
    newIsolateReceivePort.listen((dynamic message){
        CrossIsolatesMessage incomingMessage = message as CrossIsolatesMessage;
 
        //
        // 处理消息
        //
        String newMessage = "complemented string " + incomingMessage.message;
 
        //
        // 发送处理的结果
        //
        incomingMessage.sender.send(newMessage);
    });
}
 
//
// 帮助类
//
class CrossIsolatesMessage<T> {
    final SendPort sender;
    final T message;
 
    CrossIsolatesMessage({
        @required this.sender,
        this.message,
    });
}

  

1.3. 第三步:销毁这个新的 Isolate 实例

当你不再需要这个新的 Isolate 实例时,最好通过以下方法释放它:

//
// 释放一个 isolate 的例程
//
void dispose(){
    newIsolate?.kill(priority: Isolate.immediate);
    newIsolate = null;
}

  

 

1.4. 特别说明 - 单监听器流

你可能已经注意到我们正在使用流在「调用者」和新 isolate 之间进行通信。这些流的类型为:「单监听器」流。

2. 一次性计算

如果你只需要运行一些代码来完成一些特定的工作,并且在工作完成之后不需要与 Isolate 进行交互,那么这里有一个非常方便的称为 compute 的 Helper。

主要包含以下功能:

  • 产生一个 Isolate,
  • 在该 isolate 上运行一个回调函数,并传递一些数据,
  • 返回回调函数的处理结果,
  • 回调执行后终止 Isolate。

 

 

上一篇:flutter isolate demo


下一篇:定义一个常量及检查常量是否存在