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;
}@immutableclass _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);
}複製程式碼