Dart語言學習-異步編程Isolate

前言

Dart是谷歌開發的計算機編程語言,它被用于web,服務器,移動應用等領域的開發,Dart亮相于2011年,2015年5月的Dart開發者峰會上,亮相了基于Dart語言的移動應用開發框架Sky,后更名為Flutter

img.jpg

Isolate

Dart基于事件循環的異步模型,可以將耗時操作加入事件隊列中,但是事件隊列中的時間也是互相阻塞的按照順序執行,某些耗時大的操作可以使用多線程,Dart提供了Isolate可以讓多個任務并發執行

Isolate可以理解為Dart中的線程,它與線程的最大區別就是多個Isolate之間不能共享內存,這避免了線程安全問題,并且多個Isolate之間獨立垃圾回收減少了垃圾回收的性能消耗,每個Isolate都有自己的事件循環,Isolate之間通過消息進行通信

  • 多個Isolate之間不能共享內存,提高了線程安全性以及垃圾回收的性能
  • 每個Isolate都有自己獨立的事件循
  • Isolate之間通過消息進行通信
圖片6.png

創建一個新的Isolate

大部分的Dart APP運行在一個單一的Isolate中,如果情況需要我們則需要在主Isolate中創建一個新的Isolate

spawnUri
在另一個文件中,啟動一個新的main函數

  external static Future<Isolate> spawnUri(
      Uri uri, //新的Isolate文件路徑
      List<String> args, //傳遞給啟動main函數的參數列表
      var message, //其他附加參數消息
      {bool paused = false, //可選參數
      SendPort? onExit,
      SendPort? onError,
      bool errorsAreFatal = true,
      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});
//啟動SubIsolate.dart的main函數,并且傳遞參數['data1',"data2","data3"],以及對象sendPort
Isolate subIsolate = await Isolate.spawnUri(new Uri(path: "SubIsolate.dart"), ['data1',"data2","data3"], sendPort)

spawn
如果不希望出現兩個main函數,需要在同一個文件中創建一個新的Isolatespawn可以直接將一個同文件中的函數運行在另一個Isolate

//啟動一個新的Isolate,并執行load函數,傳入參數 {"args":{"data1","data2"},"sendPort":sendPort}
Isolate subIsolate = await Isolate.spawn(load, {"args":{"data1","data2"},"sendPort":sendPort});

Isolate之間進行通信

ReceivePort 用來接收SendPort發出的信息
SendPort 用來發送信息,對應一個ReceivePort,發送的信息會被ReceivePort接收
void send(Object? message) SendPort的函數永安里進行消息發送,消息內容是一個自定義的Object

main() {
  ReceivePort receivePort = new ReceivePort();
  SendPort sendPort = receivePort.sendPort;
  receivePort.listen((message) {
      print('receive $message');
      receivePort.close(); //收到消息后關閉了ReceivePort
  });
  print('listener complete');
  sendPort.send('msg');
  sendPort.send('msg1');
}
打印結果
listener complete
receive msg

使用案例
Isolate會在程序開始啟動時打印啟動時間,耗時加載圖片,打印啟動完成時間,其中加載圖片的操作需要在另一個Isolate中執行,并且當其開始執行以及執行到一半時,主Isolate需要收到消息,并且在耗時加載圖片完成之后通知主Isolate將其關閉

Isolate

printBootTime()
loadImg()
init()

import 'dart:isolate';

main(){

 printBootTime();

 loadImg();

 init();

}

printBootTime(){
  print("啟動時間"+DateTime.now().millisecondsSinceEpoch.toString());
}

loadImg() async{
  print("開始加載圖片");
  ReceivePort receivePort = new ReceivePort();
  //用于消息發送
  SendPort sendPort = receivePort.sendPort;
 //啟動一個新的Isolate 
  Isolate subIsolate = await Isolate.spawnUri(new Uri(path: "SubIsolate.dart"), ['data1',"data2","data3"], sendPort);
  receivePort.listen((message) {
    print('主Isolate收到消息 ${message[0]}');
    if(message[1] == 1){
      //進行中
    } else if(message[1] == 2){
      //加載完畢
      subIsolate.kill();
      print("子Isolate關閉");
    }
  });

}

init(){
  print("初始化參數");
}

Isolate

import 'dart:io';
import 'dart:isolate';

main(args,SendPort mainSendPort){
  print("SubIsolate.dart main args-> $args");
  mainSendPort.send(['開始進行加載',0]);
  sleep(new Duration(seconds: 2));
  mainSendPort.send(['加載中',1]);
  sleep(new Duration(seconds: 2));
  mainSendPort.send(['加載完畢',2]);
}

打印結果

啟動時間1624803408026
開始加載圖片
初始化參數
SubIsolate.dart main args-> [data1, data2, data3]
主Isolate收到消息 開始進行加載
//兩秒后
主Isolate收到消息 加載中
//兩秒后
主Isolate收到消息 加載完畢
子Isolate個關閉

案例分析

  • Isolate創建了一對消息發送/接收器
  • 在啟動子Isolate時候將主Isolate的消息發送器傳遞
  • Isolate在消息變化時,通過傳入的消息發送器發送消息,從而主可以拿到子的信息

這是案例一個單向的信息傳遞,如果消息傳遞過程中,需要主向子發送消息,則子可以通過朱德發送器以消息的形式發送子的消息發送器去到主

Future與Isolate的選擇

DartFutureIsolate均可以達到異步的效果,前者是基于事件循環的異步模型,后者是通過啟動了另一個Isolate相當于是一個輕量級的線程,Isolate雖然相比Future更有優勢,但也不能濫用

  • Isolate開銷要大于FutureFuture是執行在單線程上的異步,當線程有空閑時候就會執行耗時操作,未來回調結果,如果不是很長的耗時操作,則使用Future即可
  • 當有很長的耗時操作,推薦使用Isolate,這種情況下Isolate的大開銷是值得的,并且如果在Future上執行太長的耗時操作也會使事件隊列阻塞,導致耗時操作無法依次執行
  • 至于這個耗時的判斷,一般幾毫秒選擇Future,數百毫秒選擇Isolate
  • FutureIsolate的選擇,以及單線程語言的優劣,是一個需要持續思考的問題

歡迎關注Mike的簡書

Android 知識整理

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Dart之異步編程 本文轉載自https://www.cnblogs.com/lxlx1798/p/1112656...
    緣煥閱讀 1,345評論 0 1
  • 不知道大家有沒有一個疑問:Dart是單線程執行,那它是如何實現異步操作的呢? 本文將對Dart/Flutter提供...
    chonglingliu閱讀 1,626評論 0 2
  • 概述 Dart的異步模型 Dart的異步操作(Future以及async、await) Dart的異步補充 一、D...
    IIronMan閱讀 465評論 2 1
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月,有人笑有人哭,有人歡樂有人憂愁,有人驚喜有人失落,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,588評論 28 53
  • 信任包括信任自己和信任他人 很多時候,很多事情,失敗、遺憾、錯過,源于不自信,不信任他人 覺得自己做不成,別人做不...
    吳氵晃閱讀 6,222評論 4 8