dart系列之:dart優(yōu)秀的秘訣-隔離機(jī)制

簡(jiǎn)介

之前介紹了很多dart中的異步編程技巧骄瓣,不知道大家有沒(méi)有發(fā)現(xiàn)一個(gè)問(wèn)題械馆,如果是在java的異步編程中嫉柴,肯定會(huì)提到鎖和并發(fā)機(jī)制厌杜,但是對(duì)于dart來(lái)說(shuō),好像從來(lái)沒(méi)有聽(tīng)到多線(xiàn)程和并發(fā)的問(wèn)題差凹,這是為什么呢期奔?

今天侧馅,給大家講解一下dart中的隔離機(jī)制危尿,大家就明白了。

dart中的隔離機(jī)制

dart是一個(gè)單線(xiàn)程的語(yǔ)言馁痴,但是作為一個(gè)單線(xiàn)程的語(yǔ)言谊娇,dart卻支持Future,Stream等異步特性。這一切都是隔離機(jī)制和事件循環(huán)帶來(lái)的結(jié)果罗晕。

首先看一下dart中的隔離機(jī)制济欢。

所謂隔離指的是dart運(yùn)行的一個(gè)特定的空間,這個(gè)空間擁有單獨(dú)的內(nèi)存和單線(xiàn)程的事件循環(huán)小渊。

如下圖所示:

在java或者c++等其他語(yǔ)言中法褥,多個(gè)線(xiàn)程是共享內(nèi)存空間的,雖然帶來(lái)了并發(fā)和數(shù)據(jù)溝通的方便途徑酬屉,但是同時(shí)也造成了并發(fā)編程的困難半等。

因?yàn)槲覀冃枰紤]多線(xiàn)程之間數(shù)據(jù)的同步揍愁,于是額外多出了很多鎖的機(jī)制,詳細(xì)了解或者用過(guò)的人應(yīng)該都會(huì)很煩惱杀饵。

多線(xiàn)程最大的缺陷就是要求程序員的羅輯思維和編程技巧足夠優(yōu)秀莽囤,這樣才能夠設(shè)計(jì)出完美運(yùn)行的多線(xiàn)程程序。

但是在dart中切距,這些都不是什么問(wèn)題朽缎。dart中所有的線(xiàn)程都擁有自己的運(yùn)行空間,這個(gè)線(xiàn)程的工作就是運(yùn)行事件循環(huán)谜悟。

那么問(wèn)題來(lái)了话肖,主線(xiàn)程在處理事件循環(huán),但是如果遇到了一個(gè)非常耗時(shí)的操作赌躺,該怎么辦呢? 如果直接在主線(xiàn)程中運(yùn)行狼牺,則可能會(huì)導(dǎo)致主線(xiàn)程的阻塞。

dart也充分考慮到了這個(gè)問(wèn)題礼患,所以dart提供了一個(gè)Isolate的類(lèi)來(lái)對(duì)隔離進(jìn)行管理是钥。

因?yàn)閐art程序本身就在一個(gè)Isolate中運(yùn)行,所以如果在dart中定義一個(gè)Isolate缅叠,那么這個(gè)Isolate通常表示的是另外一個(gè)悄泥,需要和當(dāng)前Isolate進(jìn)行通信的Isolate。

生成一個(gè)Isolate

那么如何在當(dāng)前的dart程序中生成一個(gè)Isolate呢肤粱?

Isolate提供了三種生成方法弹囚。

一個(gè)非常常用的是Isolate的工廠(chǎng)方法spawn:

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

spawn會(huì)創(chuàng)建一個(gè)新的Isolate,調(diào)用它需要傳入幾個(gè)參數(shù):

entryPoint表示的是生成新Isolate的時(shí)候需要調(diào)用的函數(shù)领曼。entryPoint接受一個(gè)message參數(shù)鸥鹉。通常來(lái)說(shuō)message是一個(gè)SendPort對(duì)象,用于兩個(gè)Isolate之間的溝通庶骄。

paused表示新生成的Isolate是否處于暫停狀態(tài)毁渗,他相當(dāng)于:

isolate.pause(isolate.pauseCapability)

如果后續(xù)需要取消暫停狀態(tài),則可以調(diào)用:

isolate.resume(isolate.pauseCapability)

errorsAreFatal 對(duì)應(yīng)的是setErrorsFatal方法单刁。

onExit對(duì)應(yīng)的是addOnExitListener, onError對(duì)應(yīng)的是addErrorListener灸异。

debugName表示的是Isolate在調(diào)試的時(shí)候展示的名字。

如果spawn出錯(cuò)羔飞,則會(huì)拋出IsolateSpawnException異常:

class IsolateSpawnException implements Exception {
  /// Error message reported by the spawn operation.
  final String message;
  @pragma("vm:entry-point")
  IsolateSpawnException(this.message);
  String toString() => "IsolateSpawnException: $message";
}

spawn方法生成的是和當(dāng)前代碼一樣的Isolate肺樟。如果想要使用不同的代碼來(lái)生成,則可以使用spawnUri,通過(guò)傳入對(duì)應(yīng)的Uri地址逻淌,從而生成不一樣的code么伯。

external static Future<Isolate> spawnUri(
      Uri uri,
      List<String> args,
      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});

還有一種方式,就是使用Isolate的構(gòu)造函數(shù):

Isolate(this.controlPort, {this.pauseCapability, this.terminateCapability});

它有三個(gè)參數(shù)卡儒,第一個(gè)參數(shù)是controlPort田柔,代表另外一個(gè)Isolate的控制權(quán)誓篱,后面兩個(gè)capabilities是原isolate的子集,表示是否有pause或者terminate的權(quán)限凯楔。

一般用法如下:

Isolate isolate = findSomeIsolate();
Isolate restrictedIsolate = Isolate(isolate.controlPort);
untrustedCode(restrictedIsolate);

Isolate之間的交互

所有的dart代碼都是運(yùn)行在Isolate中的窜骄,然后代碼只能夠訪(fǎng)問(wèn)同一個(gè)isolate內(nèi)的class和value。那么多個(gè)isolate之間通信摆屯,可以ReceivePort和SendPort來(lái)實(shí)現(xiàn)邻遏。

先看下SendPort,SendPort是Capability的一種:

abstract class SendPort implements Capability 

SendPort用于向ReceivePort發(fā)送message, message可以有很多類(lèi)型,包括:

Null,bool,int,double,String,List,Map,TransferableTypedData,SendPort和Capability虐骑。

注意准验,send動(dòng)作是立馬完成的。

事實(shí)上廷没,SendPort是由ReceivePort來(lái)創(chuàng)建的糊饱。一個(gè)ReceivePort可以接收多個(gè)SendPort。

ReceivePort是Stream的一種:

abstract class ReceivePort implements Stream<dynamic>

作為Stream,它提供了一個(gè)listen用來(lái)處理接收到的消息:

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

一個(gè)例子

講了那么多原理颠黎,有的同學(xué)可能會(huì)問(wèn)了另锋,那么到底怎么用呢?

例子來(lái)了:

import 'dart:isolate';

var isolate;

void entryPoint(SendPort sendPort) {
  int counter = 0;
  sendPort.send("counter:$counter");
}
void main() async{
  final receiver = ReceivePort();
  receiver.listen((message) {
    print( "接收到消息 $message");
  });
  isolate = await Isolate.spawn(entryPoint, receiver.sendPort);
}

在主線(xiàn)程中狭归,我們創(chuàng)建了一個(gè)ReceivePort夭坪,然后調(diào)用了它的listen方法來(lái)監(jiān)聽(tīng)sendPort發(fā)過(guò)來(lái)的消息。

然后spawn出一個(gè)新的Isolate过椎,這個(gè)Isolate會(huì)在初始化之后室梅,調(diào)用entryPoint方法。

在這個(gè)entryPoint方法中又使用sendPort向ReceivePort發(fā)送消息疚宇。

最終運(yùn)行亡鼠,打印:

接收到消息 counter:0

總結(jié)

以上就是dart中的隔離機(jī)制和Isolate的使用敷待。

本文已收錄于 http://www.flydean.com/25-dart-isolates/

最通俗的解讀间涵,最深刻的干貨,最簡(jiǎn)潔的教程讼撒,眾多你不知道的小技巧等你來(lái)發(fā)現(xiàn)浑厚!

歡迎關(guān)注我的公眾號(hào):「程序那些事」,懂技術(shù)股耽,更懂你根盒!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市物蝙,隨后出現(xiàn)的幾起案子炎滞,更是在濱河造成了極大的恐慌,老刑警劉巖诬乞,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件册赛,死亡現(xiàn)場(chǎng)離奇詭異钠导,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)森瘪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)牡属,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人扼睬,你說(shuō)我怎么就攤上這事逮栅。” “怎么了窗宇?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵措伐,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我军俊,道長(zhǎng)侥加,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任粪躬,我火速辦了婚禮担败,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘镰官。我一直安慰自己氢架,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布朋魔。 她就那樣靜靜地躺著岖研,像睡著了一般。 火紅的嫁衣襯著肌膚如雪警检。 梳的紋絲不亂的頭發(fā)上孙援,一...
    開(kāi)封第一講書(shū)人閱讀 50,096評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音扇雕,去河邊找鬼拓售。 笑死,一個(gè)胖子當(dāng)著我的面吹牛镶奉,可吹牛的內(nèi)容都是我干的础淤。 我是一名探鬼主播,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼哨苛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鸽凶!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起建峭,我...
    開(kāi)封第一講書(shū)人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤玻侥,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后亿蒸,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體凑兰,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掌桩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了姑食。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片波岛。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖音半,靈堂內(nèi)的尸體忽然破棺而出盆色,到底是詐尸還是另有隱情,我是刑警寧澤祟剔,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布隔躲,位于F島的核電站,受9級(jí)特大地震影響物延,放射性物質(zhì)發(fā)生泄漏宣旱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一叛薯、第九天 我趴在偏房一處隱蔽的房頂上張望浑吟。 院中可真熱鬧,春花似錦耗溜、人聲如沸组力。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)燎字。三九已至,卻和暖如春阿宅,著一層夾襖步出監(jiān)牢的瞬間候衍,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工洒放, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蛉鹿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓往湿,卻偏偏與公主長(zhǎng)得像妖异,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子领追,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容