Day04-Dart-基礎(chǔ)語法三:異步

概述

  • Dart的異步模型
  • Dart的異步操作(Future以及async述吸、await)
  • Dart的異步補充
一盏求、Dart的異步模型
  • 1.1噪漾、Dart是單線程的

    • 1.1.1、程序中的耗時操作
      開發(fā)中的耗時操作:

      • 在開發(fā)中蜂莉,我們經(jīng)常會遇到一些耗時的操作需要完成蜡娶,比如網(wǎng)絡(luò)請求、文件讀取等等映穗;
      • 如果我們的主線程一直在等待這些耗時的操作完成窖张,那么就會進行阻塞,無法響應(yīng)其它事件男公,比如用戶的點擊荤堪;顯然,我們不能這么干J嗯狻澄阳!

      如何處理耗時的操作呢?針對如何處理耗時的操作踏拜,不同的語言有不同的處理方式碎赢。

      • 處理方式一: 多線程,比如Java速梗、C++肮塞,我們普遍的做法是開啟一個新的線程(Thread)襟齿,在新的線程中完成這些異步的操作,再通過線程間通信的方式枕赵,將拿到的數(shù)據(jù)傳遞給主線程猜欺。
      • 處理方式二: 單線程+事件循環(huán),比如JavaScript拷窜、Dart都是基于單線程加事件循環(huán)來完成耗時操作的處理开皿。不過單線程如何能進行耗時的操作呢?
    • 1.1.2. 單線程的異步操作
      我之前碰到很多開發(fā)者都對單線程的異步操作充滿了問號篮昧?赋荆??
      其實它們并不沖突:

      • 因為我們的一個應(yīng)用程序大部分時間都是處于空閑的狀態(tài)的懊昨,并不是無限制的在和用戶進行交互窄潭。
      • 比如等待用戶點擊、網(wǎng)絡(luò)請求數(shù)據(jù)的返回酵颁、文件讀寫的IO操作嫉你,這些等待的行為并不會阻塞我們的線程;
      • 這是因為類似于網(wǎng)絡(luò)請求材义、文件讀寫的 IO均抽,我們都可以基于非阻塞調(diào)用嫁赏;

      阻塞式調(diào)用和非阻塞式調(diào)用
      如果想搞懂這個點其掂,我們需要知道操作系統(tǒng)中的阻塞式調(diào)用和非阻塞式調(diào)用的概念。

      • 阻塞和非阻塞關(guān)注的是 程序在等待調(diào)用結(jié)果(消息潦蝇,返回值)時的狀態(tài)款熬。
      • 阻塞式調(diào)用: 調(diào)用結(jié)果返回之前,當(dāng)前線程會被掛起攘乒,調(diào)用線程只有在得到調(diào)用結(jié)果之后才會繼續(xù)執(zhí)行贤牛。
      • 非阻塞式調(diào)用: 調(diào)用執(zhí)行之后,當(dāng)前線程不會停止執(zhí)行则酝,只需要過一段時間來檢查一下有沒有結(jié)果返回即可殉簸。
  • 1.2、Dart 事件循環(huán)

    • 1.2.1沽讹、什么是事件循環(huán)?
      單線程模型中主要就是在維護著一個事件循環(huán)(Event Loop)般卑。
      事件循環(huán)是什么呢?

      • 事實上事件循環(huán)并不復(fù)雜爽雄,它就是將需要處理的一系列事件(包括點擊事件蝠检、IO事件、網(wǎng)絡(luò)事件)放在一個事件隊列(Event Queue)中挚瘟。
      • 不斷的從事件隊列(Event Queue)中取出事件叹谁,并執(zhí)行其對應(yīng)需要執(zhí)行的代碼塊饲梭,直到事件隊列清空位置。

      我們來寫一個事件循環(huán)的偽代碼:

      // 這里我使用數(shù)組模擬隊列, 先進先出的原則
      List eventQueue = []; 
      var event;
      
      // 事件循環(huán)從啟動的一刻焰檩,永遠在執(zhí)行
      while (true) {
          if (eventQueue.length > 0) {
             // 取出一個事件
             event = eventQueue.removeAt(0);
             // 執(zhí)行該事件
             event();000000000000000000000000000000000
          }
      }
      

      當(dāng)我們有一些事件時憔涉,比如點擊事件、IO事件析苫、網(wǎng)絡(luò)事件時监氢,它們就會被加入到eventLoop中,當(dāng)發(fā)現(xiàn)事件隊列不為空時發(fā)現(xiàn)藤违,就會取出事件浪腐,并且執(zhí)行。


      事件循環(huán)

      齒輪就是我們的事件循環(huán)顿乒,它會從隊列中一次取出事件來執(zhí)行议街。

    • 1.2.2、事件循環(huán)代碼模擬
      這里我們來看一段偽代碼璧榄,理解點擊事件和網(wǎng)絡(luò)請求的事件是如何被執(zhí)行的:
      這是一段Flutter代碼特漩,很多東西大家可能不是特別理解,但是耐心閱讀你會讀懂我們在做什么骨杂。
      一個按鈕 RaisedButton涂身,當(dāng)發(fā)生點擊時執(zhí)行 onPressed 函數(shù)。
      onPressed 函數(shù)中搓蚪,我們發(fā)送了一個網(wǎng)絡(luò)請求蛤售,請求成功后會執(zhí)行then中的回調(diào)函數(shù)。

      RaisedButton(
          child: Text('Click me'),
          onPressed: () {
             final myFuture = http.get('https://example.com');
             myFuture.then((response) {
                 if (response.statusCode == 200) {
                     print('Success!');
                 }
             });
          },
      )
      

      這些代碼是如何放在事件循環(huán)中執(zhí)行呢妒潭?

      • 1悴能、當(dāng)用戶發(fā)生點擊的時候,onPressed回調(diào)函數(shù)被放入事件循環(huán)中執(zhí)行雳灾,執(zhí)行的過程中發(fā)送了一個網(wǎng)絡(luò)請求漠酿。
      • 2、網(wǎng)絡(luò)請求發(fā)出去后谎亩,該事件循環(huán)不會被阻塞炒嘲,而是發(fā)現(xiàn)要執(zhí)行的onPressed函數(shù)已經(jīng)結(jié)束,會將它丟棄掉匈庭。
      • 3夫凸、網(wǎng)絡(luò)請求成功后,會執(zhí)行then中傳入的回調(diào)函數(shù)嚎花,這也是一個事件寸痢,該事件被放入到事件循環(huán)中執(zhí)行,執(zhí)行完畢后紊选,事件循環(huán)將其丟棄啼止。

      盡管 onPressed 和 then 中的回調(diào)有一些差異道逗,但是它們對于事件循環(huán)來說,都是告訴它:我有一段代碼需要執(zhí)行献烦,快點幫我完成滓窍。【

二巩那、Dart的異步操作

Dart中的異步操作主要使用Future以及async吏夯、await。
如果你之前有過前端的ES6即横、ES7編程經(jīng)驗噪生,那么完全可以將Future理解成Promise,async东囚、await和ES7中基本一致跺嗽。
但是如果沒有前端開發(fā)經(jīng)驗,F(xiàn)uture以及async页藻、await如何理解呢桨嫁?

  • 2.1、認(rèn)識 Future

    • 2.1.1份帐、同步 的網(wǎng)絡(luò)請求
      我們先來看一個例子吧:在這個例子中璃吧,我使用getNetworkData來模擬了一個網(wǎng)絡(luò)請求;該網(wǎng)絡(luò)請求需要3秒鐘的時間废境,之后返回數(shù)據(jù)畜挨;

      main(List<String> args) {
          print('開始請求');
          String result = getNetworkData();
          print('$result');
          print('結(jié)束請求');
      }
      
      String getNetworkData() {
          sleep(Duration(seconds: 3));
          return "我是請求到的數(shù)據(jù)";
      }
      

      這段代碼會運行怎么的結(jié)果:getNetworkData會阻塞main函數(shù)的執(zhí)行

      開始請求
      // 等待 3 秒
      我是請求到的數(shù)據(jù)
      結(jié)束請求
      

      顯然,上面的代碼不是我們想要的執(zhí)行效果彬坏,因為網(wǎng)絡(luò)請求阻塞了main 函數(shù)朦促,那么意味著其后所有的代碼都無法正常的繼續(xù)執(zhí)行。

    • 2.1.2栓始、異步的網(wǎng)絡(luò)請求
      我們來對我們上面的代碼進行改進,和剛才的代碼唯一的區(qū)別在于我使用了Future對象來將耗時的操作放在了其中傳入的函數(shù)中血当;代碼如下:

      import 'dart:io';
      
      main(List<String> args) {
          print('開始請求');
          var future = getNetworkData();
          future.then((String value) {
             print("結(jié)果:$value");
          }).catchError((error) {
             print('$error');
          }).whenComplete(() {
             print('代碼執(zhí)行完成');
          });
      
          print('結(jié)束請求');
      }
      
      // 模擬一個網(wǎng)絡(luò)請求
      Future<String> getNetworkData() {
          return Future<String>(() {
              // 將耗時操作包裹到 Future的函數(shù)回調(diào)中
              // 1>幻赚、只要有返回結(jié)果,那么就執(zhí)行 Future對應(yīng)的回調(diào)(Promise-resolve)
              // 2>臊旭、如果沒有結(jié)果返回(有錯誤信息)落恼,需要在 Future 會調(diào)中跑出一個異常(Promise-reject)
              sleep(Duration(seconds: 3));
              throw Exception("我是錯誤信息");
              // return "我是請求到的數(shù)據(jù)";  
          });
      }
      

      提示:

      • 1、請求錯誤拋出異常:throw Exception("我是錯誤信息");
      • 2离熏、代碼執(zhí)行完:whenComplete
  • 2.1.3. Future 使用補充

    • Future 的鏈?zhǔn)秸{(diào)用:可以在 then 中繼續(xù)返回值佳谦,會在下一個鏈?zhǔn)降膖hen調(diào)用回調(diào)函數(shù)中拿到返回的結(jié)果,實例代碼如下

      import 'dart:io';
      
      main(List<String> args) {
      
         print('start');
      
         Future(() {
           sleep(Duration(seconds: 3));
           throw Exception("第一次異常");
           // return '第1次網(wǎng)絡(luò)請求的結(jié)果';
         }).then((result) {
           print('$result');
           sleep(Duration(seconds: 3));
           return '第2次網(wǎng)絡(luò)請求的結(jié)果';
         }).then((result) {
           print('$result');
           sleep(Duration(seconds: 3));
           return '第3次網(wǎng)絡(luò)請求的結(jié)果';
         }).then((result) {
           print('$result');
         }).catchError((error){
           print(error);
         });
      
         print('end');
      }
      

      打印結(jié)果如下:

      start
      end
      第1次的結(jié)果
      第2次的結(jié)果
      第3次的結(jié)果
      
    • Future 其他API

      • Future.value(value)滋戳,直接獲取一個完成的Future钻蔑,該Future會直接調(diào)用then的回調(diào)函數(shù)

        main(List<String> args) {
           print('Main Start');
        
           Future.value('內(nèi)容').then((value) {
              print(value);
           });
        
           print('Main End');
        }
        

        打印結(jié)果如下:

        Main Start
        Main End
        內(nèi)容
        

        疑惑:為什么立即執(zhí)行啥刻,但是哈哈哈是在最后打印的呢?
        這是因為Future中的then會作為新的任務(wù)會加入到事件隊列中(Event Queue)咪笑,加入之后你肯定需要排隊執(zhí)行了

      • Future.error(object):直接獲取一個完成的Future可帽,但是是一個發(fā)生異常的Future,該Future會直接調(diào)用catchError的回調(diào)函數(shù)

        main(List<String> args) {
           print("main function start");
        
           Future.error(Exception("錯誤信息")).catchError((error) {
               print(error);
           });
        
           print("main function end");
        }
        

        打印結(jié)果如下:

        main function start
        main function end
        Exception: 錯誤信息
        
      • Future.delayed(時間, 回調(diào)函數(shù)):在延遲一定時間時執(zhí)行回調(diào)函數(shù)窗怒,執(zhí)行完回調(diào)函數(shù)后會執(zhí)行 then 的回調(diào)映跟;

        main(List<String> args) {
          print("main function start");
        
          Future.delayed(Duration(seconds: 3), () {
              return "3秒后的信息";
          }).then((value) {
              print(value);
          });
        
          print("main function end");
        }
        
  • 2.2、await扬虚、async

    • 2.2.1努隙、理論概念理解
      如果你已經(jīng)完全搞懂了Future,那么學(xué)習(xí)await辜昵、async應(yīng)該沒有什么難度剃法。
      await、async是什么呢路鹰?

      • 它們是Dart中的關(guān)鍵字(你這不是廢話嗎贷洲?廢話也還是要強調(diào)的,萬一你用它做變量名呢晋柱。)
      • 它們可以讓我們用 同步的代碼格式优构,去實現(xiàn)異步的調(diào)用過程
      • 并且雁竞,通常一個async的函數(shù)會返回一個Future(別著急钦椭,馬上就看到代碼了)。

      我們已經(jīng)知道碑诉,F(xiàn)uture可以做到不阻塞我們的線程彪腔,讓線程繼續(xù)執(zhí)行,并且在完成某個操作時改變自己的狀態(tài)进栽,并且回調(diào)then或者errorCatch回調(diào)德挣。
      如何生成一個Future呢?

      • 1快毛、通過我們前面學(xué)習(xí)的Future構(gòu)造函數(shù)格嗅,或者后面學(xué)習(xí)的Future其他API都可以。
      • 2唠帝、還有一種就是通過async的函數(shù)屯掖。
    • 2.2.2、案例代碼演練
      我們來對之前的Future異步處理代碼進行改造襟衰,改成await贴铜、async的形式。
      我們知道,如果直接這樣寫代碼绍坝,代碼是不能正常執(zhí)行的:

      • 因為 Future.delayed 返回的是一個Future對象徘意,我們不能把它看成同步的返回數(shù)據(jù):"network data"去使用

      • 也就是我們不能把這個異步的代碼當(dāng)做同步一樣去使用!

        main(List<String> args) {
           print("main function start");
           print(getNetworkData());
           print("main function end");
        }
        
        String getNetworkData() {
           var result = Future.delayed(Duration(seconds: 3), () {
              return "network data";
           }).then((value) {
              print('結(jié)果是:$value');
           });
        
           print("哈哈");
           return  "請求到的數(shù)據(jù):$result";
        }
        

        打印結(jié)果如下

        main function start
        哈哈
        請求到的數(shù)據(jù):Instance of 'Future<String>'
        main function end
        結(jié)果是:network data
        

        現(xiàn)在我使用 await 修改下面這句代碼:1陷嘴、你會發(fā)現(xiàn)映砖,我在Future.delayed函數(shù)前加了一個await。2灾挨、一旦有了這個關(guān)鍵字邑退,那么這個操作就會等待Future.delayed的執(zhí)行完畢,并且等待它的結(jié)果劳澄。

        Future<String> getNetworkData() async {
            var result = await Future.delayed(Duration(seconds: 3), () {
                 return "network data";
            }).then((value) {
                 print('結(jié)果是:$value');
            });
            print("哈哈");
            return  "請求到的數(shù)據(jù):$result";
        }
        
        • 提示:
        • 1地技、await關(guān)鍵字必須存在于async函數(shù)中。
        • 2秒拔、使用async標(biāo)記的函數(shù)莫矗,必須返回一個Future對象。
        • 3砂缩、我們現(xiàn)在可以像同步代碼一樣去使用Future異步返回的結(jié)果作谚;等待拿到結(jié)果之后和其他數(shù)據(jù)進行拼接,然后一起返回庵芭;返回的時候并不需要包裝一個Future妹懒,直接返回即可,但是返回值會默認(rèn)被包裝在一個Future中双吆;
三眨唬、Dart的異步補充
  • 3.1、任務(wù)執(zhí)行順序

    • 3.1.1好乐、認(rèn)識微任務(wù)隊列
      在前面學(xué)習(xí)學(xué)習(xí)中匾竿,我們知道Dart中有一個事件循環(huán)(Event Loop)來執(zhí)行我們的代碼,里面存在一個事件隊列(Event Queue)蔚万,事件循環(huán)不斷從事件隊列中取出事件執(zhí)行岭妖。
      但是如果我們嚴(yán)格來劃分的話,在Dart中還存在另一個隊列:微任務(wù)隊列(Microtask Queue)笛坦。

      • 微任務(wù)隊列的優(yōu)先級要高于事件隊列区转;
      • 也就是說事件循環(huán)都是優(yōu)先執(zhí)行微任務(wù)隊列中的任務(wù),再執(zhí)行 事件隊列 中的任務(wù)版扩;

      那么在Flutter開發(fā)中,哪些是放在事件隊列侄泽,哪些是放在微任務(wù)隊列呢礁芦?

      • 所有的外部事件任務(wù)都在事件隊列中,如IO、計時器柿扣、點擊肖方、以及繪制事件等;
      • 而微任務(wù)通常來源于Dart內(nèi)部未状,并且微任務(wù)非常少俯画。這是因為如果微任務(wù)非常多,就會造成事件隊列排不上隊司草,會阻塞任務(wù)隊列的執(zhí)行(比如用戶點擊沒有反應(yīng)的情況)艰垂;

      說道這里,你可能已經(jīng)有點凌亂了埋虹,在Dart的單線程中猜憎,代碼到底是怎樣執(zhí)行的呢?

      • 1搔课、Dart的入口是main函數(shù)胰柑,所以main函數(shù)中的代碼會優(yōu)先執(zhí)行;
      • 2爬泥、main函數(shù)執(zhí)行完后柬讨,會啟動一個事件循環(huán)(Event Loop)就會啟動,啟動后開始執(zhí)行隊列中的任務(wù)袍啡;
      • 3踩官、首先,會按照先進先出的順序葬馋,執(zhí)行 微任務(wù)隊列(Microtask Queue)中的所有任務(wù)卖鲤;
      • 4、其次畴嘶,會按照先進先出的順序蛋逾,執(zhí)行 事件隊列(Event Queue)中的所有任務(wù);
    • 3.1.2窗悯、如何創(chuàng)建微任務(wù)
      在開發(fā)中区匣,我們可以通過dart中async下的scheduleMicrotask來創(chuàng)建一個微任務(wù):

      import "dart:async";
      
      main(List<String> args) {
          scheduleMicrotask(() {
             print("Hello Microtask");
          });
      }
      

      在開發(fā)中,如果我們有一個任務(wù)不希望它放在Event Queue中依次排隊蒋院,那么就可以創(chuàng)建一個微任務(wù)了亏钩。
      Future的代碼是加入到事件隊列還是微任務(wù)隊列呢?
      Future中通常有兩個函數(shù)執(zhí)行體:

      • Future構(gòu)造函數(shù)傳入的函數(shù)體
      • then的函數(shù)體(catchError等同看待)

      那么它們是加入到什么隊列中的呢欺旧?

      • Future構(gòu)造函數(shù)傳入的函數(shù)體放在事件隊列中

      • then的函數(shù)體要分成三種情況:

      • 情況一:Future沒有執(zhí)行完成(有任務(wù)需要執(zhí)行)姑丑,那么then會直接被添加到Future的函數(shù)執(zhí)行體后;

      • 情況二:如果Future執(zhí)行完后就then辞友,該then的函數(shù)體被放到如微任務(wù)隊列栅哀,當(dāng)前Future執(zhí)行完后執(zhí)行微任務(wù)隊列震肮;

      • 情況三:如果Future是鏈?zhǔn)秸{(diào)用,意味著then未執(zhí)行完留拾,下一個then不會執(zhí)行戳晌;

        // future_1加入到eventqueue中,緊隨其后then_1被加入到eventqueue中
        Future(() => print("future_1")).then((_) => print("then_1"));
        
        // Future沒有函數(shù)執(zhí)行體痴柔,then_2被加入到microtaskqueue中
        Future(() => null).then((_) => print("then_2"));
        
        // future_3沦偎、then_3_a、then_3_b依次加入到eventqueue中
        Future(() => print("future_3")).then((_) => print("then_3_a")).then((_) => print("then_3_b"));
        
      • 3.1.3. 代碼執(zhí)行順序

        import "dart:async";
        
        main(List<String> args) {
          print("main start");
        
          Future(() => print("task1"));
        
          final future = Future(() => null);
        
          Future(() => print("task2")).then((_) {
              print("task3");
              scheduleMicrotask(() => print('task4'));
          }).then((_) => print("task5"));
        
          future.then((_) => print("task6"));
          scheduleMicrotask(() => print('task7'));
        
          Future(() => print('task8')).then((_) => Future(() => print('task9'))).then((_) => print('task10'));
        
          print("main end");
        }
        

        代碼執(zhí)行的結(jié)果是:

        main start
        main end
        task7
        task1
        task6
        task2
        task3
        task5
        task4
        task8
        task9
        task10
        

        代碼分析:

        • 1咳蔚、main函數(shù)先執(zhí)行豪嚎,所以main start和main end先執(zhí)行,沒有任何問題屹篓;
        • 2疙渣、main函數(shù)執(zhí)行過程中,會將一些任務(wù)分別加入到EventQueue和MicrotaskQueue中堆巧;
        • 3妄荔、task7通過scheduleMicrotask函數(shù)調(diào)用,所以它被最早加入到MicrotaskQueue谍肤,會被先執(zhí)行啦租;
        • 4、然后開始執(zhí)行EventQueue荒揣,task1被添加到EventQueue中被執(zhí)行篷角;
        • 5、通過final future = Future(() => null);創(chuàng)建的future的then被添加到微任務(wù)中,微任務(wù)直接被優(yōu)先執(zhí)行,所以會執(zhí)行task6滑沧;
        • 6、一次在EventQueue中添加task2嘉蕾、task3、task5被執(zhí)行霜旧;
        • 7错忱、task3的打印執(zhí)行完后,調(diào)用scheduleMicrotask挂据,那么在執(zhí)行完這次的EventQueue后會執(zhí)行以清,所以在task5后執(zhí)行task4(注意:scheduleMicrotask的調(diào)用是作為task3的一部分代碼,所以task4是要在task5之后執(zhí)行的)
        • 8崎逃、task8掷倔、task9、task10一次添加到EventQueue被執(zhí)行个绍;

        事實上今魔,上面的代碼執(zhí)行順序有可能出現(xiàn)在面試中勺像,我們開發(fā)中通常不會出現(xiàn)這種復(fù)雜的嵌套障贸,并且需要完全搞清楚它的執(zhí)行順序错森;
        但是,了解上面的代碼執(zhí)行順序篮洁,會讓你對EventQueuemicrotaskQueue有更加深刻的理解涩维。

  • 3.2. 多核CPU的利用

    • 3.2.1. Isolate 的理解
      在Dart中,有一個Isolate的概念袁波,它是什么呢瓦阐?

      • 我們已經(jīng)知道Dart是單線程的,這個線程有自己可以訪問的內(nèi)存空間以及需要運行的事件循環(huán)篷牌;
      • 我們可以將這個空間系統(tǒng)稱之為是一個Isolate睡蟋;
      • 比如Flutter中就有一個Root Isolate,負責(zé)運行Flutter的代碼枷颊,比如UI渲染戳杀、用戶交互等等;

      在 Isolate 中夭苗,資源隔離做得非常好信卡,每個 Isolate 都有自己的 Event Loop 與 Queue,

      • Isolate 之間不共享任何資源题造,只能依靠消息機制通信傍菇,因此也就沒有資源搶占問題。

      但是界赔,如果只有一個Isolate丢习,那么意味著我們只能永遠利用一個線程,這對于多核CPU來說淮悼,是一種資源的浪費咐低。
      如果在開發(fā)中,我們有非常多耗時的計算敛惊,完全可以自己創(chuàng)建Isolate渊鞋,在獨立的Isolate中完成想要的計算操作。
      如何創(chuàng)建Isolate呢瞧挤?我們通過Isolate.spawn就可以創(chuàng)建了:如下

      import "dart:isolate";
      
      main(List<String> args) {
         Isolate.spawn(foo, "Hello Isolate");
      }
      
      void foo(info) {
         print("新的isolate:$info");
      }
      

      提示:Isolate.spawn(foo, "Hello Isolate");第一個參數(shù)是函數(shù)名锡宋,第二個是參數(shù)

    • 3.2.2. Isolate通信機制
      但是在真實開發(fā)中,我們不會只是簡單的開啟一個新的Isolate特恬,而不關(guān)心它的運行結(jié)果:

    • 我們需要新的Isolate進行計算执俩,并且將計算結(jié)果告知Main Isolate(也就是默認(rèn)開啟的Isolate);

    • Isolate 通過發(fā)送管道(SendPort)實現(xiàn)消息通信機制癌刽;

    • 我們可以在啟動并發(fā)Isolate時將Main Isolate的發(fā)送管道作為參數(shù)傳遞給它役首;

    • 并發(fā)在執(zhí)行完畢時尝丐,可以利用這個管道給Main Isolate發(fā)送消息;

      import "dart:isolate";
      
      main(List<String> args) async {
         // 1.創(chuàng)建管道
         ReceivePort receivePort= ReceivePort();
      
         // 2.創(chuàng)建新的Isolate
         Isolate isolate = await Isolate.spawn<SendPort>(foo, receivePort.sendPort);
      
         // 3.監(jiān)聽管道消息
         receivePort.listen((data) {
            print('Data:$data');
            // 不再使用時衡奥,我們會關(guān)閉管道
            receivePort.close();
            // 需要將isolate殺死
            isolate?.kill(priority: Isolate.immediate);
         });
      }
      
      void foo(SendPort sendPort) {
         sendPort.send("Hello World");
      }
      

      但是我們上面的通信變成了單向通信爹袁,如果需要雙向通信呢?

      • 事實上雙向通信的代碼會比較麻煩矮固;
      • Flutter提供了支持并發(fā)計算的 compute 函數(shù)失息,它內(nèi)部封裝了 Isolate 的創(chuàng)建和雙向通信;
      • 利用它我們可以充分利用多核心CPU档址,并且使用起來也非常簡單盹兢;

      注意:下面的代碼不是dart的API,而是Flutter的API守伸,所以只有在Flutter項目中才能運行

      main(List<String> args) async {
         int result = await compute(powerNum, 5);
         print(result);
      }
      
      int powerNum(int num) {
          return num * num;
      }
      

      提示:compute(powerNum, 5); 傳入的 函數(shù) 必須是全局的方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末绎秒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子尼摹,更是在濱河造成了極大的恐慌见芹,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窘问,死亡現(xiàn)場離奇詭異辆童,居然都是意外死亡,警方通過查閱死者的電腦和手機惠赫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門把鉴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人儿咱,你說我怎么就攤上這事庭砍。” “怎么了混埠?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵怠缸,是天一觀的道長。 經(jīng)常有香客問我钳宪,道長揭北,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任吏颖,我火速辦了婚禮搔体,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘半醉。我一直安慰自己疚俱,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布缩多。 她就那樣靜靜地躺著呆奕,像睡著了一般养晋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上梁钾,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天绳泉,我揣著相機與錄音,去河邊找鬼陈轿。 笑死圈纺,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的麦射。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼灯谣,長吁一口氣:“原來是場噩夢啊……” “哼潜秋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起胎许,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤峻呛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后辜窑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钩述,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年穆碎,在試婚紗的時候發(fā)現(xiàn)自己被綠了牙勘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡所禀,死狀恐怖方面,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情色徘,我是刑警寧澤恭金,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站褂策,受9級特大地震影響横腿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜斤寂,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一耿焊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扬蕊,春花似錦搀别、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蒂培。三九已至,卻和暖如春榜苫,著一層夾襖步出監(jiān)牢的瞬間护戳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工垂睬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留媳荒,地道東北人。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓驹饺,卻偏偏與公主長得像钳枕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子赏壹,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355