<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      干貨 | Dart 并發機制詳解

      Dart 通過 async-await、isolate 以及一些異步類型概念 (例如 FutureStream) 支持了并發代碼編程。本篇文章會對 async-await、FutureStream
      進行簡略的介紹,而側重點放在 isolate 的講解上。

      在應用中,所有的 Dart 代碼都在 isolate 中運行。每一個 Dart 的 isolate 都有獨立的運行線程,它們無法與其他 isolate 共享可變對象。在需要進行通信的場景里,isolate 會使用消息機制。盡管 Dart 的 isolate 模型設計是基于操作系統提供的進程和線程等更為底層的原語進行設計的,但在本篇文章中,我們不對其具體實現展開討論。

      大部分 Dart 應用只會使用一個 isolate (即 主 isolate),同時你也可以創建更多的 isolate,從而在多個處理器內核上達成并行執行代碼的目的。

      多平臺使用時注意

      所有的 Dart 應用都可以使用 async-await、FutureStream
      而 isolate 僅針對 原生平臺的使用 進行實現。
      使用 Dart 構建的網頁應用可以 使用 Web Workers 實現相似的功能。

      異步的類型和語法

      如果你已經對 FutureStream 和 async-await 比較熟悉了,可以直接跳到 isolate 部分進行閱讀。

      Future 和 Stream 類型

      Dart 語言和庫通過 FutureStream 對象,來提供會在當前調用的未來返回某些值的功能。以 JavaScript 中的 Promise 為例,在 Dart 中一個最終會返回 int 類型值的 promise,應當聲明為 Future<int>;一個會持續返回一系列 int 類型值的 promise,應當聲明為 Stream<int>

      讓我們用 dart:io 來舉另外一個例子。File 的同步方法 readAsStringSync() 會以同步調用的方式讀取文件,在讀取完成或者拋出錯誤前保持阻塞。這個會返回 String 類型的對象,或者拋出異常。而與它等效的異步方法 readAsString(),會在調用時立刻返回 Future<String> 類型的對象。在未來的某一刻,Future<String> 會結束,并返回一個字符串或錯誤。

      為什么一個方法是同步的還是異步的會如此重要?因為大部分應用需要在同一時刻做很多件事。例如,應用可能會發起一個 HTTP 請求,同時在請求返回前對用戶的操作做出不同的界面更新。異步的代碼會有助于應用保持更高的可交互狀態。

      async-await 語法

      asyncawait 關鍵字是用聲明來定義異步函數和獲取它們的結果的方式。

      下面是一段同步代碼調用文件 I/O 時阻塞的例子:

      void main() {
        // Read some data.
        final fileData = _readFileSync();
        final jsonData = jsonDecode(fileData);
      
        // Use that data.
        print('Number of JSON keys: ${jsonData.length}');
      }
      
      String _readFileSync() {
        final file = File(filename);
        final contents = file.readAsStringSync();
        return contents.trim();
      }
      

      下面是類似的代碼,但是變成了 異步調用

      void main() async {
        // Read some data.
        final fileData = await _readFileAsync();
        final jsonData = jsonDecode(fileData);
      
        // Use that data.
        print('Number of JSON keys: ${jsonData.length}');
      }
      
      Future<String> _readFileAsync() async {
        final file = File(filename);
        final contents = await file.readAsString();
        return contents.trim();
      }
      

      main() 函數在調用 _readFileAsync() 前使用了 await 關鍵字,讓原生代碼 (文件 I/O) 執行的同時,其他的 Dart 代碼 (例如事件處理器) 能繼續執行。使用 await 后,_readFileAsync() 調用返回的 Future<String> 類型也轉換為了 String。從而在將結果 content 賦予變量時,隱式轉換為 String 類型。

      await 關鍵字僅在函數體前定義了 async 的函數中有效。

      如下圖所示,無論是在 Dart VM 還是在系統中,Dart 代碼都會在 readAsString() 執行非 Dart 代碼時暫停。在 readAsString() 返回值后,Dart 代碼將繼續執行。

      如果你想了解更多關于 asyncawaitFuture 的內容,可以訪問
      異步編程 codelab 進行學習。

      Isolate 的工作原理

      現代的設備通常會使用多核 CPU。開發者為了讓程序在設備上有更好的表現,有時會使用共享內容的線程來并發運行代碼。然而,狀態的共享可能會 產生競態條件,從而造成錯誤
      也可能會增加代碼的復雜度。

      Dart 代碼并不在多個線程上運行,取而代之的是它們會在 isolate 內運行。每一個 isolate 會有自己的堆內存,從而確保 isolate 之間互相隔離,無法互相訪問狀態。
      由于這樣的實現并不會共享內存,所以你也不需要擔心 互斥鎖和其他鎖)。

      在使用 isolate 時,你的 Dart 代碼可以在同一時刻進行多個獨立的任務,并且使用可用的處理器核心。Isolate 與線程和進程近似,但是每個 isolate 都擁有獨立的內存,以及運行事件循環的獨立線程。

      主 isolate

      在一般場景下,你完全無需關心 isolate。通常一個 Dart 應用會在主 isolate 下執行所有代碼,如下圖所示:

      就算是只有一個 isolate 的應用,只要通過使用 async-await 來處理異步操作,也完全可以流暢運行。一個擁有良好性能的應用,會在快速啟動后盡快進入事件循環。這使得應用可以通過異步操作快速響應對應的事件。

      Isolate 的生命周期

      如下圖所示,每個 isolate 都是從運行 Dart 代碼開始的,比如 main() 函數。執行的 Dart 代碼可能會注冊一些事件監聽,例如處理用戶操作或文件讀寫。當 isolate 執行的 Dart 代碼結束后,如果它還需要處理已監聽的事件,那么它依舊會繼續被保持。處理完所有事件后,isolate 會退出。

      事件處理

      在客戶端應用中,主 isolate 的事件隊列內,可能會包含重繪的請求、點擊的通知或者其他界面事件。例如,下圖展示了包含四個事件的事件隊列,隊列會按照先進先出的模式處理事件。

      如下圖所示,在 main() 方法執行完畢后,事件隊列中的處理才開始,此時處理的是第一個重繪的事件。而后主 isolate 會處理點擊事件,接著再處理另一個重繪事件。

      如果某個同步執行的操作花費了很長的處理時間,應用看起來就像是失去了響應。在下圖中,處理點擊事件的代碼比較耗時,導致緊隨其后的事件并沒有及時處理。這時應用可能會產生卡頓,所有的動畫都無法流暢播放。

      在一個客戶端應用中,耗時過長的同步操作,通常會導致 卡頓的動畫。而最糟糕的是,應用界面可能完全失去響應。

      后臺運行對象

      如果你的應用受到耗時計算的影響而出現卡頓,例如 解析較大的 JSON 文件
      你可以考慮將耗時計算轉移到單獨工作的 isolate,通常我們稱這樣的 isolate 為 后臺運行對象。下圖展示了一種常用場景,你可以生成一個 isolate,它將執行耗時計算的任務,并在結束后退出。這個 isolate 工作對象退出時會把結果返回。

      每個 isolate 都可以通過消息通信傳遞一個對象,這個對象的所有內容都需要滿足可傳遞的條件。并非所有的對象都滿足傳遞條件,在無法滿足條件時,消息發送會失敗。
      舉個例子,如果你想發送一個 List<Object>,你需要確保這個列表中所有元素都是可被傳遞的。假設這個列表中有一個 Socket,由于它無法被傳遞,所以你無法發送整個列表。

      你可以查閱 send() 方法 的文檔來確定哪些類型可以進行傳遞。

      Isolate 工作對象可以進行 I/O 操作、設置定時器,以及其他各種行為。它會持有自己內存空間,與主 isolate 互相隔離。這個 isolate 在阻塞時也不會對其他 isolate 造成影響。

      代碼示例

      本節將重點討論使用 Isolate API 實現 isolate 的一些示例。

      Flutter 開發提示

      如果你在非 Web 平臺上使用 Flutter 進行開發,那么與其直接使用 Isolate API,可以考慮使用 Flutter 提供的 compute() 方法compute() 方法能以簡單的方式將一個函數的調用封裝至 isolate 工作對象內。

      實現一個簡單的 isolate 工作對象

      本節將展示一個主 isolate 與它生成的 isolate 工作對象的實現。Isolate 工作對象會執行一個函數,完成后結束對象,并將函數結果發送至主 isolate。(Flutter 提供的 compute() 方法也是以類似的方式工作的。)

      下面的示例將使用到這些與 isolate 相關的 API:

      主 isolate 的代碼如下:

      void main() async {
        // Read some data.
        final jsonData = await _parseInBackground();
      
        // Use that data
        print('number of JSON keys = ${jsonData.length}');
      }
      
      // Spawns an isolate and waits for the first message
      Future<Map<String, dynamic>> _parseInBackground() async {
        final p = ReceivePort();
        await Isolate.spawn(_readAndParseJson, p.sendPort);
        return await p.first;
      }
      

      _parseInBackground() 方法包含了 生成 后臺 isolate 工作對象的代碼,并返回結果:

      1. 在生成 isolate 之前,代碼創建了一個 ReceivePort,讓 isolate 工作對象可以傳遞信息至主 isolate。
      2. 接下來是調用 Isolate.spawn(),生成并啟動一個在后臺運行的 isolate 工作對象。該方法的第一個參數是 isolate 工作對象執行的函數引用:_readAndParseJson。第二個參數則是 isolate 用來與主 isolate 傳遞消息的 SendPort。此處的代碼并沒有 創建 新的 SendPort,而是直接使用了 ReceivePortsendPort 屬性。
      3. Isolate 初始化完成后,主 isolate 即開始等待它的結果。由于 ReceivePort 實現了 Stream,你可以很方便地使用 first 屬性獲得 isolate 工作對象返回的單個消息。

      初始化后的 isolate 會執行以下代碼:

      Future _readAndParseJson(SendPort p) async {
        final fileData = await File(filename).readAsString();
        final jsonData = jsonDecode(fileData);
        Isolate.exit(p, jsonData);
      }
      

      在最后一句代碼后,isolate 會退出,將 jsonData 通過傳入的 SendPort 發送。
      在 isolate 之間傳遞消息時,通常會發生數據拷貝,所耗費的時間隨著數據的大小而發生改變,復雜度為 O(n)。然而,當你使用 Isolate.exit() 發送數據時,isolate 中持有的消息并沒有發生拷貝,而是直接轉移到了接收的 isolate 中。這樣的轉移速度很快,耗費的時間復雜度僅為 O(1)

      Isolate.exit() 在 Dart 2.15 中被引入

      在先前的 Dart 版本中,僅支持通過 Isolate.send() 進行顯式的消息傳遞,
      下一個小節的示例中將進行說明。

      下圖說明了主 isolate 和 isolate 工作對象之間的通信流程:

      在 isolate 之間發送多次消息內容

      如果你想在 isolate 之間建立更多的通信,那么你需要使用 SendPortsend() 方法。下圖展示了一種常見的場景,主 isolate 會發送請求消息至 isolate 工作對象,然后它們之間會繼續進行多次通信,進行請求和回復。

      下方列舉的 isolate 示例 包含了發送多次消息的使用方法:

      • send_and_receive.dart 展示了如何從主 isolate 發送消息至生成的 isolate。與前面的示例較為接近。
      • long_running_isolate.dart 展示了如何生成一個長期運行、且多次發送和接收消息的 isolate。

      性能和 isolate 組

      當一個 isolate 調用了 Isolate.spawn(),兩個 isolate 將擁有同樣的執行代碼,并歸入同一個 isolate 組 中。Isolate 組會帶來性能優化,例如新的 isolate 會運行由 isolate 組持有的代碼,即共享代碼調用。同時,Isolate.exit() 僅在對應的 isolate 屬于同一組時有效。

      某些場景下,你可能需要使用 Isolate.spawnUri(),使用執行的 URI 生成新的 isolate,并且包含代碼的副本。然而,spawnUri() 會比 spawn() 慢很多,并且新生成的 isolate 會位于新的 isolate 組。另外,當 isolate 在不同的組中,它們之間的消息傳遞會變得更慢。

      在 Flutter 開發中請注意

      Flutter 不支持 Isolate.spawnUri()

      文章信息

      posted on 2022-01-18 11:03  Flutter社區  閱讀(910)  評論(0)    收藏  舉報

      導航

      主站蜘蛛池模板: 高清无码爆乳潮喷在线观看| 蜜桃无码一区二区三区| 欧美亚洲熟妇一区二区三区| 国产亚洲精品VA片在线播放| 亚洲国产精品综合久久网络| 欧美日本在线一区二区三区| 四虎成人精品在永久在线| 毛片无遮挡高清免费| 久久青草国产精品一区| 中文在线天堂中文在线天堂| 老司机精品影院一区二区三区| 亚洲性日韩精品一区二区三区| 精品乱人码一区二区二区| 亚洲国产精品综合久久网络| 亚洲人成网站在线播放动漫| 国产老熟女无套内射不卡| 97久久人人超碰国产精品| 国产玖玖玖玖精品电影| 无码人妻斩一区二区三区| 又爽又黄又无遮挡的视频| 特级毛片a片久久久久久| 强开少妇嫩苞又嫩又紧九色| 乱熟女高潮一区二区在线| 女同亚洲精品一区二区三| 国产精品午夜福利91| 国产精品自在线拍国产手青青机版| 精品久久久久久国产| 亚洲欧美日韩成人综合一区 | 风间由美性色一区二区三区| 国产av一区二区三区无码野战| 91中文字幕一区二区| 成人性生交大片免费看r链接| 亚洲宅男精品一区在线观看| 国产女高清在线看免费观看| 亚洲成人av一区二区| 亚洲欧美日韩成人综合一区| 久久99精品久久久久久9| 久久精品国产www456c0m| 国产短视频精品一区二区| 水蜜桃精品综合视频在线| 亚洲国产中文字幕在线视频综合|