天天看點

Flutter 92: 圖解 Dart 單線程實作異步處理之 Isolate (一)

      小菜剛嘗試了 Future 和 async-await 實作的簡單異步操作,但對于耗時較長的異步該如何處理呢?對于 Android 來說可以新開一個線程單獨處理,而對應的 Dart 可以用 Isolate 來處理;

Isolate

      Isolate 是對 Dart 并發模式的實作,類似于 Android 中的 Thread 線程,但與 Thread 有本質的差別,Thread 可以實作記憶體共享,而 Isolate 不能;

      所有的 Dart Code 都是在 Isolate 中執行的,代碼隻能使用同一個 Isolate 中的内容,Isolate 有自己的記憶體和事件循環機制;不同的 Isolate 是記憶體隔離的,是以隻能通過 Port 機制發送消息通信,其原理是向不同的 Isolate 隊列中執行寫任務;

Isolate 的建立

      Isolate 一般通過 spawn / spawnUri 來建立對象;

Isolate.spawn()
external static Future<Isolate> spawn<T>(
  void entryPoint(T message), T message,
  {bool paused: false,
  bool errorsAreFatal,
  SendPort onExit,
  SendPort onError,
  @Since("2.3") String debugName});           

      簡單了解源碼,spawn 必須的參數包括需要耗時操作的 entryPoint 和 T 任意類型的 message 資料,即 Isolate 中可以傳遞任意類型的資料;

_loadIsolateDate() async {
  await Isolate.spawn(_backgroundWork, ReceivePort().sendPort);
}

static _backgroundWork(SendPort sendPort) {
  sendPort.send('BackgroundWork -> currentTime -> ${DateTime.now().millisecondsSinceEpoch}');
}           
Isolate.spawnUri()
external static Future<Isolate> spawnUri(
  Uri uri,
  List<String> args,
  var message,
  {bool paused: false,
  SendPort onExit,
  SendPort onError,
  bool errorsAreFatal,
  bool checked,
  Map<String, String> environment,
  @Deprecated('The packages/ dir is not supported in Dart 2')
      Uri packageRoot,
  Uri packageConfig,
  bool automaticPackageResolution: false,
  @Since("2.3")
      String debugName});           

      簡單了解源碼,spawnUri 需要三個必要參數,uri 為其他 Isolate 代碼檔案的路徑;清單 args 為傳遞的參數清單,message 動态消息,一般是 SendPort;

_loadIsolateDate03() async {
  ReceivePort receivePort = ReceivePort();
  await Isolate.spawnUri(new Uri(path: "./utils/second_isolate.dart"),
      ['params01, params02, params03'], receivePort.sendPort);
  receivePort.listen((val) => print('listen -> 【$val】'));
}           

Isolate 的通訊

      Isolate 可以友善的利用多核 CPU 來處理耗時操作,因記憶體不共享,需要通過 Port 進行消息通訊;其中 Port 消息傳遞也是異步的;

單向通訊

      Port 一般是成對出現,分别是 ReceivePort 接收端口和 SendPort 發送端口;而 ReceivePort 也可以生成自己的 SendPort;隻需要把 SendPort 傳遞給其他 Isolate 即可;

_loadIsolateDate01() async {
  ReceivePort receivePort = ReceivePort();
  await Isolate.spawn(_backgroundWork, receivePort.sendPort);
  receivePort.listen((val) => print('listen -> 【$val】'));
}

static _backgroundWork(SendPort sendPort) async {
  sendPort.send(
      'BackgroundWork -> currentTime -> ${DateTime.now().millisecondsSinceEpoch}');
  Future.delayed(Duration(seconds: 3), () {
    return sendPort.send(
        'BackgroundWork delayed 3s -> currentTime -> ${DateTime.now().millisecondsSinceEpoch}');
  });
}           
Flutter 92: 圖解 Dart 單線程實作異步處理之 Isolate (一)
雙向通訊

      雙向通訊與單向通訊一樣,把雙方的 SendPort 互相傳遞即可;

_loadIsolateDate02() async {
  ReceivePort receivePort = ReceivePort();
  var sendPort;
  await Isolate.spawn(_backgroundWork2, receivePort.sendPort);
  receivePort.listen((val) {
    if (val is SendPort) {
      sendPort = val as SendPort;
      print("雙向通訊建立成功");
    }
    print("Isolate Recevie Data -> 【$val】");
    if (sendPort != null) {
      sendPort.send('_loadIsolateDate02 -> currentTime -> ${DateTime.now().millisecondsSinceEpoch}');
    }
  });
}

static _backgroundWork2(SendPort sendPort) async {
  ReceivePort receivePort = new ReceivePort();
  receivePort.listen((val) {
    print("Background Isolate Receive Data -> 【$val]");
  });
  sendPort.send('BackgroundWork -> currentTime -> ${DateTime.now().millisecondsSinceEpoch}');
  sendPort.send(receivePort.sendPort);
  Future.delayed(Duration(seconds: 2), () {
    return sendPort.send('BackgroundWork delayed 2s -> currentTime -> ${DateTime.now().millisecondsSinceEpoch}');
  });
  Future.delayed(Duration(seconds: 5), () {
    return sendPort.send(receivePort.sendPort);
  });
}           
Flutter 92: 圖解 Dart 單線程實作異步處理之 Isolate (一)

Isolate 的銷毀

      Isolate 就像機器中的一個小空間,有自己的記憶體塊,是以在使用 Isolate 結束後應及時關閉并銷毀目前 Isolate;

isolate.kill(priority: Isolate.immediate);           

Tips

Q:Invalid argument(s): Isolate.spawn expects to be passed a static or top-level function

      小菜剛開始建立 Isolate 時,遇到如下錯誤;

Flutter 92: 圖解 Dart 單線程實作異步處理之 Isolate (一)

A:

      需要将 Isolate.spawn 中的 message 參數方法設定成 static 方法或放置在 main() 入口;

      由于篇幅和測試案例不足,小菜分為兩篇小部落格對 Isolate 進行學習,對異步的認知還不夠深入;如有錯誤請多多指導!

來源: 阿策小和尚

繼續閱讀