【Flutter 專題】93 圖解 Dart 單執行緒實現非同步處理之 Isolate (二)

阿策小和尚發表於2021-07-16

      小菜剛學習了 Isolate 的部分基本用法,今天繼續嘗試 compute 及其使用方式;

Isolate

      小菜之前瞭解到 ReceivePortSendPort 是成對出現的,是 Isolate 之間唯一的訊息通訊的方式;

ReceivePort

abstract class ReceivePort implements Stream {
  external factory ReceivePort();

  external factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort);

  StreamSubscription listen(void onData(var message),
      {Function onError, void onDone(), bool cancelOnError});

  void close();

  SendPort get sendPort;
}
複製程式碼

      簡單分析原始碼可得,ReceivePort 中通過 get 獲取一個 SendPort 物件,通過 SendPort 傳送訊息到 ReceivePort 中,之後再通過 listen 進行監聽;

SendPort

abstract class SendPort implements Capability {
  void send(var message);

  bool operator ==(var other);

  int get hashCode;
}
複製程式碼

      SendPort 內容很簡單,主要是通過 send 方法向 ReceivePort 傳遞訊息;

Compute

      小菜嘗試了 Isolate 的基本用法,需要使用 ReceivePortSendPort 來進行訊息通訊;而 Flutter 提供了更簡單的 Compute Function

原始碼分析

Future<R> compute<Q, R>(isolates.ComputeCallback<Q, R> callback, Q message, { String debugLabel }) async {
  ...
  final Isolate isolate = await Isolate.spawn<_IsolateConfiguration<Q, FutureOr<R>>>(_spawn,
    _IsolateConfiguration<Q, FutureOr<R>>(
      callback, message,
      resultPort.sendPort,
      debugLabel, flow.id,
    ),
    errorsAreFatal: true,
    onExit: resultPort.sendPort,
    onError: errorPort.sendPort,
  );
  final Completer<R> result = Completer<R>();
  errorPort.listen((dynamic errorData) {
    ...
  });
  resultPort.listen((dynamic resultData) {
    ...
  });
  await result.future;
  Timeline.startSync('$debugLabel: end', flow: Flow.end(flow.id));
  resultPort.close();
  errorPort.close();
  isolate.kill();
  Timeline.finishSync();
  return result.future;
}
複製程式碼

      簡單瞭解原始碼,Compute 實際是對 Isolate 的封裝,Compute 是通過 Isolate.spawn() 方式來處理 Isolate 其中 compute() 方法中在通訊結束後自動進行 Isolate.kill() 銷燬;且 compute() 直接返回內容,無需考慮 listen 監聽等;

案例嘗試

      compute() 包含兩個必填引數,第一個是定義新的 Isolate 的核心執行方法,第二個是函式對應的引數,可以是多個任意型別;因為 compute 實際是通過 Isolate.spawn() 來處理的,則對應的耗時方法也需要是在頂級 main 函式中或 static 方法;

_loadIsolateDate04() async {
  print('main Isolate, current Isolate = ${Isolate.current.hashCode}');
  print(await compute(getName, ''));
}

static String getName(String name) {
  print('new Isolate, current Isolate = ${Isolate.current.hashCode}');
  sleep(Duration(seconds: 2));
  return '阿策小和尚';
}
複製程式碼

      對於 compute() 的異常處理,可以通過 try-catch 進行捕獲;

_loadIsolateDate05(bool isError) async {
  print('main Isolate, current Isolate = ${Isolate.current.hashCode}');
  try {
    print(await compute(_backgroundWork3, isError));
  } catch (e) {
    print(e);
  }
}

static _backgroundWork3(bool isError) async {
  print('new Isolate, current Isolate = ${Isolate.current.hashCode}');
  if (!isError) {
    return await Future.delayed(Duration(seconds: 2), () {
      return 'BackgroundWork delayed 2s -> currentTime -> ${DateTime.now().millisecondsSinceEpoch}';
    });
  } else {
    return await Future.error(ArgumentError.notNull('Input'));
  }
}
複製程式碼


      Isolate 案例嘗試


      小菜對 Isolate 的原始碼還未深入研究,僅停留在應用層;如有錯誤請多多指導!

來源: 阿策小和尚

相關文章