深入了解Flutter的isolate(4) --- 使用Compute写isolate

    xiaoxiao2022-07-12  148

    转载:https://juejin.im/post/5c3a06f56fb9a049d37f54f4

    0x00 前言

    前面讲了如何创建isolate,这篇文章讲创建isolate的另一种方法。

    0x01 使用isolates的方法

    使用isolates的方法种:

    高级API:Compute函数 (用起来方便)低级API:ReceivePort

    0x02 Compute函数

    Compute函数对isolate的创建和底层的消息传递进行了封装,使得我们不必关系底层的实现,只需要关注功能实现。

    首先我们需要:

    一个函数:必须是顶级函数或静态函数一个参数:这个参数是上面的函数定义入参(函数没有参数的话就没有)

    比如,还是计算斐波那契数列:

    void main() async{ //调用compute函数,compute函数的参数就是想要在isolate里运行的函数,和这个函数需要的参数 print( await compute(syncFibonacci, 20)); runApp(MyApp()); } int syncFibonacci(int n){ return n < 2 ? n : syncFibonacci(n-2) + syncFibonacci(n-1); } 复制代码

    运行后的结果如下:

    flutter: 6765 复制代码

    是不是很简单,接下来看下compute函数的源码,这里的代码有点复杂,会把分析的添加到代码的注释里,首先介绍一个compute函数里用到的函数别名:

    ComputeCallback<Q, R>定义如下:

    // Q R是泛型,ComputeCallback是一个有参数Q,返回值为R的函数 typedef ComputeCallback<Q, R> = R Function(Q message); 复制代码

    正式看源码:

    //compute函数 必选参数两个,已经讲过了 Future<R> compute<Q, R>(ComputeCallback<Q, R> callback, Q message, { String debugLabel }) async { //如果是在profile模式下,debugLabel为空的话,就取callback.toString() profile(() { debugLabel ??= callback.toString(); }); final Flow flow = Flow.begin(); Timeline.startSync('$debugLabel: start', flow: flow); final ReceivePort resultPort = ReceivePort(); Timeline.finishSync(); //创建isolate,这个和前面讲的创建isolate的方法一致 //还有一个,这里传过去的参数是用_IsolateConfiguration封装的类 final Isolate isolate = await Isolate.spawn<_IsolateConfiguration<Q, R>>( _spawn, _IsolateConfiguration<Q, R>( callback, message, resultPort.sendPort, debugLabel, flow.id, ), errorsAreFatal: true, onExit: resultPort.sendPort, ); final R result = await resultPort.first; Timeline.startSync('$debugLabel: end', flow: Flow.end(flow.id)); resultPort.close(); isolate.kill(); Timeline.finishSync(); return result; } @immutable class _IsolateConfiguration<Q, R> { const _IsolateConfiguration( this.callback, this.message, this.resultPort, this.debugLabel, this.flowId, ); final ComputeCallback<Q, R> callback; final Q message; final SendPort resultPort; final String debugLabel; final int flowId; R apply() => callback(message); } void _spawn<Q, R>(_IsolateConfiguration<Q, R> configuration) { R result; Timeline.timeSync( '${configuration.debugLabel}', () { result = configuration.apply(); }, flow: Flow.step(configuration.flowId), ); Timeline.timeSync( '${configuration.debugLabel}: returning result', () { configuration.resultPort.send(result); }, flow: Flow.step(configuration.flowId), ); } 复制代码

    0x03 ReceivePort

    import 'dart:async'; import 'dart:io'; import 'dart:isolate'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; //一个普普通通的Flutter应用的入口 //main函数这里有async关键字,是因为创建的isolate是异步的 void main() async{ runApp(MyApp()); //asyncFibonacci函数里会创建一个isolate,并返回运行结果 print(await asyncFibonacci(20)); } //这里以计算斐波那契数列为例,返回的值是Future,因为是异步的 Future<dynamic> asyncFibonacci(int n) async{ //首先创建一个ReceivePort,为什么要创建这个? //因为创建isolate所需的参数,必须要有SendPort,SendPort需要ReceivePort来创建 final response = new ReceivePort(); //开始创建isolate,Isolate.spawn函数是isolate.dart里的代码,_isolate是我们自己实现的函数 //_isolate是创建isolate必须要的参数。 await Isolate.spawn(_isolate,response.sendPort); //获取sendPort来发送数据 final sendPort = await response.first as SendPort; //接收消息的ReceivePort final answer = new ReceivePort(); //发送数据 sendPort.send([n,answer.sendPort]); //获得数据并返回 return answer.first; } //创建isolate必须要的参数 void _isolate(SendPort initialReplyTo){ final port = new ReceivePort(); //绑定 initialReplyTo.send(port.sendPort); //监听 port.listen((message){ //获取数据并解析 final data = message[0] as int; final send = message[1] as SendPort; //返回结果 send.send(syncFibonacci(data)); }); } int syncFibonacci(int n){ return n < 2 ? n : syncFibonacci(n-2) + syncFibonacci(n-1); }

     

    最新回复(0)