持續發燒,聊聊Dart語言的併發處理,能挑戰Go不?

sincermc發表於2021-07-30

  前言

  貌似關於Dart的文章沒流量啊,就算在小編關懷上了首頁,看得人還是很少的。

  算了,今天持續發燒,再來寫寫如何使用 Dart 語言的併發操作。說起併發操作,玩 Go 的同學該笑了,這就是我們的看家本領啊。玩 PHP 的同學繼續看看,表示我們光看不說話。

  程式碼演示之前,我們先假設一個場景。假設我有一些漂亮妹妹,他們要出門旅行了,旅行的時候會發照片給我。在這裡個過程中,程式碼需要做的事情:

  接收請求

  安排出行計劃,同時出行哦,不能有先後之分

  他們各自出行,可以發照片給我

  返回結果

  這個過程中,我關心的是他們能不能處理好自己的事情,因為我妹妹太多了,如果都讓我幫他們,累死我也搞不定啊,我就幹兩件事,安排好出行計劃,最後收照片。

  程式碼演示一下吧

  import 'dart:io';

  import 'dart:isolate';

  main() async {

  print(DateTime.now().toString() + ' 開始');

  //這是一個接收埠,可以理解成我的手機

  ReceivePort receivePort = new ReceivePort();

  //安排三個妹妹出去旅行,讓她們牢記我的手機號

  await Isolate.spawn(travelToBeijing, receivePort.sendPort);

  await Isolate.spawn(travelToShanghai, receivePort.sendPort);

  await Isolate.spawn(travelToGuangzhou, receivePort.sendPort);

  //我就在手機上,等待他們的訊息

  receivePort.listen((message) {

  print(message);

  });

  print(DateTime.now().toString() + ' 結束');

  }

  void travelToBeijing(SendPort sendPort) {

  sleep(Duration(seconds: 3));

  sendPort.send(DateTime.now().toString() + ' 我是妹妹1,我在北京了');

  }

  void travelToShanghai(SendPort sendPort) {

  sleep(Duration(seconds: 3));

  sendPort.send(DateTime.now().toString() + ' 我是妹妹2,我在上海了');

  }

  void travelToGuangzhou(SendPort sendPort) {

  sleep(Duration(seconds: 3));

  sendPort.send(DateTime.now().toString() + ' 我是妹妹3,我在廣州了');

  }

  上面寫了那麼多,都是啥意思呢,我自己稍微解釋下上面的程式碼。

  Dart 裡的併發,用到的是 Isolate 類。

  Isolate 翻譯過來即是 隔離區, 是 Dart 實現併發的重要類。它併發的原理,既不是多程式,也不是多執行緒,你說類似於 Go 的協程吧,也不像。

  真的很難定義它,期待對作業系統研究更深的同學來佈道,當然這不影響我們使用。

  Isolate.spawn 來定義一個併發任務,接收兩個引數,第一個是該任務的處理函式,第二個是該處理函式的所需要的引數

  ReceivePort 翻譯一下 接收埠, 也可以翻譯成 接收器,用來接收各個任務回傳的訊息。

  receivePort.listen 用來監聽各任務的回傳資訊,程式碼裡只是簡單列印

  執行它,得到列印的結果

  2021-07-01 15:40:38.132122 開始

  2021-07-01 15:40:38.295683 結束

  2021-07-01 15:40:41.200316 我是妹妹1,我在北京了

  2021-07-01 15:40:41.248851 我是妹妹2,我在上海了

  2021-07-01 15:40:41.296737 我是妹妹3,我在廣州了

  注意看列印結果,妹妹們很乖,基本在同一時間給我回復了訊息。總共時間差不多3秒鐘,你可以新增更多工,都會是3秒鐘。

  再次封裝一下

  實際使用的時候,我們可以再次封裝,使用的同學不用去想 Isolate, ReceivePort 都是什麼鬼

  import 'dart:io';

  import 'dart:isolate';

  class MultiTask {

  static void run(

  {List<TaskItem> taskList,

  Function taskFunc,

  Function onCompletedItem,

  Function onCompletedAll}) async {

  ReceivePort receivePort = new ReceivePort();

  Map<String, Isolate> mapParam = {};

  for (int i = 0; i < taskList.length; i++) {

  TaskItem taskItem = taskList[i];

  mapParam[taskItem.key] = await Isolate.spawn(

  taskFunc, TaskMessage(receivePort.sendPort, taskItem));

  }

  List<TaskRes> taskResList = [];

  receivePort.listen((message) async {

  TaskRes taskRes = message as TaskRes;

  if (null != onCompletedItem) await onCompletedItem(taskRes);

  taskResList.add(taskRes);

  mapParam[taskRes.key].kill();

  if (taskResList.length == taskList.length) {

  receivePort.close();

  if (null != onCompletedAll) await onCompletedAll(taskResList);

  }

  });

  }

  }

  class TaskMessage {

  SendPort sendPort;

  TaskItem taskItem;

  TaskMessage(this.sendPort, this.taskItem);

  }

  class TaskItem {

  String key;

  String param;

  TaskItem(this.key, this.param);

  }

  class TaskRes {

  String key;

  String res;

  TaskRes(this.key, this.res);

  }

  使用的時候,這樣來:

  import 'dart:io';

  import 'dart:isolate';

  import 'MultiTask.dart';

  main() async {

  List<TaskItem> taskList = [

  TaskItem('1', 'param1'),

  TaskItem('2', 'param2'),

  TaskItem('3', 'param1'),

  TaskItem('4', 'param2'),

  TaskItem('5', 'param1'),

  TaskItem('6', 'param2'),

  TaskItem('7', 'param1'),

  TaskItem('8', 'param2'),

  TaskItem('9', 'param1'),

  TaskItem('0', 'param2'),

  ];

  print(DateTime.now());

  MultiTask.run(

  taskList: taskList,

  taskFunc: taskFunc,

  onCompletedItem: (TaskRes taskRes) =>

  print(DateTime.now().toString() + '_' + taskRes.res),

  onCompletedAll: (List<TaskRes> taskResList) =>

  print(DateTime.now().toString() + '_onCompletedAll'),

  );

  }

  void taskFunc(TaskMessage taskMessage) async {

  sleep(Duration(seconds: 3));

  String res = 'onCompletedItem is ok';

  taskMessage.sendPort.send(TaskRes(taskMessage.taskItem.key, res));

  }

  走起來吧

  2021-07-01 15:50:54.862973

  2021-07-01 15:50:57.924675_onCompletedItem is ok

  2021-07-01 15:50:57.954982_onCompletedItem is ok

  2021-07-01 15:50:57.986042_onCompletedItem is ok

  2021-07-01 15:50:58.021282_onCompletedItem is ok

  2021-07-01 15:50:58.053387_onCompletedItem is ok

  2021-07-01 15:50:58.088492_onCompletedItem is ok

  2021-07-01 15:50:58.121968_onCompletedItem is ok

  2021-07-01 15:50:58.157117_onCompletedItem is ok

  2021-07-01 15:50:58.190835_onCompletedItem is ok

  2021-07-01 15:50:58.229044_onCompletedItem is ok

  2021-07-01 15:50:58.241011_onCompletedAll

  可以看到,中間每一個任務完成的時間,都很接近,併發處理很完美

  總結

  當需要處理很多工時,可以開闢多個隔離區,併發執行,提高效率。

  Dart語言對併發的處理,還算人性化,理解起來沒有難度,用起來也容易。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69999012/viewspace-2784258/,如需轉載,請註明出處,否則將追究法律責任。

相關文章