日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

聊一聊Flutter Engine线程管理与Dart Isolate机制

發布時間:2024/9/3 编程问答 57 豆豆
生活随笔 收集整理的這篇文章主要介紹了 聊一聊Flutter Engine线程管理与Dart Isolate机制 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

阿里妹導讀:Flutter是一款開源的移動跨平臺UI開發套件,它不僅與現存的Native代碼兼容,還能幫你用Dart語言快速開發高質量的跨平臺App。

本文由閑魚技術團隊福居撰寫,結合Flutter Engine官方文檔討論了Flutter Engine內的線程管理模式以及Dart Isolate機制,希望與大家一起探討。

在終端業務需求日益復雜,版本迭代日趨于頻繁的情況下,我們迫切需要優秀的多端統一跨平臺開發方案以提升研發效率。目前已有類似RN,Weex這種通過JavaScript橋接到Native的終端技術方案。但是,基于JavaScript的橋接模式有JavaScriptCore自身的性能瓶頸和橋接層的消耗。

目前閑魚團隊在積極嘗試和探索Flutter在業務中的實踐以追求更加高效,高性能的跨平臺終端方案。同為跨平臺技術,Flutter有何優勢呢?

  • Flutter在Rlease模式下直接將Dart編譯成本地機器碼,避免了代碼解釋運行的性能消耗。
  • Dart本身針對高頻率循環刷新(如屏幕每秒60幀)在內存層面進行了優化,使得Dart運行時在屏幕繪制實現如魚得水。
  • Flutter實現了自己的圖形繪制避免了Native橋接。

Flutter在應用層使用Dart進行開發,而支撐它的是用C++開發的引擎。

為了更好地應用和實踐,我們需要深入到引擎內部去理解的它的實現原理和構造。線程一直是在開發當中令人比較頭疼的話題,我們也在實踐過程中踩過不少坑,本文就Flutter引擎的線程模式進行一些探討。

Flutter 線程管理

Flutter Engine要求Embeder提供四個Task Runner,Embeder指的是將引擎移植到平臺的中間層代碼。這四個主要的Task Runner包括:

Platform Task Runner

Flutter Engine的主Task Runner,類似于Android Main Thread或者iOS的Main Thread。但是需要注意他們還是有區別的。

一般來說,一個Flutter應用啟動的時候會創建一個Engine實例,Engine創建的時候會創建一個線程供Platform Runner使用。

跟Flutter Engine的所有交互(接口調用)必須在Platform Thread進行,否則可能導致無法預期的異常。這跟iOS UI相關的操作都必須在主線程進行相類似。需要注意的是在Flutter Engine中有很多模塊都是非線程安全的。

規則很簡單,對于Flutter Engine的接口調用都需保證在Platform Thread進行。

阻塞Platform Thread不會直接導致Flutter應用的卡頓(跟iOS android主線程不同)。盡管如此,也不建議在這個Runner執行繁重的操作,長時間卡住Platform Thread應用有可能會被系統Watchdog強殺。

UI Task Runner Thread(Dart Runner)

UI Task Runner用于執行Dart root isolate代碼(isolate我們后面會講到,姑且先簡單理解為Dart VM里面的線程)。Root isolate比較特殊,它綁定了不少Flutter需要的函數方法,以便進行渲染相關操作。對于每一幀,引擎要做的事情有:

  • Root isolate通知Flutter Engine有幀需要渲染。
  • Flutter Engine通知平臺,需要在下一個vsync的時候得到通知。
  • 平臺等待下一個vsync
  • 對創建的對象和Widgets進行Layout并生成一個Layer Tree,這個Tree馬上被提交給Flutter Engine。當前階段沒有進行任何光柵化,這個步驟僅是生成了對需要繪制內容的描述。
  • 創建或者更新Tree,這個Tree包含了用于屏幕上顯示Widgets的語義信息。這個東西主要用于平臺相關的輔助Accessibility元素的配置和渲染。

除了渲染相關邏輯之外Root Isolate還是處理來自Native Plugins的消息,Timers,Microtasks和異步IO等操作。Root Isolate負責創建管理的Layer Tree最終決定繪制到屏幕上的內容。因此這個線程的過載會直接導致卡頓掉幀。

GPU Task Runner

GPU Task Runner主要用于執行設備GPU的指令。UI Task Runner創建的Layer Tree是跨平臺的,它不關心到底由誰來完成繪制。GPU Task Runner負責將Layer Tree提供的信息轉化為平臺可執行的GPU指令。GPU Task Runner同時負責繪制所需要的GPU資源的管理。資源主要包括平臺Framebuffer,Surface,Texture和Buffers等。

一般來說UI Runner和GPU Runner跑在不同的線程。GPU Runner會根據目前幀執行的進度去向UI Runner要求下一幀的數據,在任務繁重的時候可能會告訴UI Runner延遲任務。這種調度機制確保GPU Runner不至于過載,同時也避免了UI Runner不必要的消耗。

建議為每一個Engine實例都新建一個專用的GPU Runner線程。

IO Task Runner

前面討論的幾個Runner對于執行流暢度有比較高的要求。Platform Runner過載可能導致系統WatchDog強殺,UI和GPU Runner過載則可能導致Flutter應用的卡頓。但是GPU線程的一些必要操作,例如IO,放到哪里執行呢?答案正是IO Runner。

IO Runner的主要功能是從圖片存儲(比如磁盤)中讀取壓縮的圖片格式,將圖片數據進行處理為GPU Runner的渲染做好準備。IO Runner首先要讀取壓縮的圖片二進制數據(比如PNG,JPEG),將其解壓轉換成GPU能夠處理的格式然后將數據上傳到GPU。

獲取諸如ui.Image這樣的資源只有通過async call去調用,當調用發生的時候Flutter Framework告訴IO Runner進行加載的異步操作。

IO Runner直接決定了圖片和其它一些資源加載的延遲間接影響性能。所以建議為IO Runner創建一個專用的線程。

各個平臺目前默認Runner線程實現

前面我們提到Engine Runner的線程可以按照實際情況進行配置,各個平臺目前有自己的實現策略。

iOS和Android

Mobile平臺上面每一個Engine實例啟動的時候會為UI,GPU,IO Runner各自創建一個新的線程。所有Engine實例共享同一個Platform Runner和線程。

Fuchsia

每一個Engine實例都為UI,GPU,IO,Platform Runner創建各自新的線程。

自定義配置線程可行方案

我們注意到Mobile平臺上面,Platform Runner和Thread是共享的。引擎源碼如下:

這里我們可以進行改動,讓引擎每個實例初始化獨自的線程:

理論上你可以配置任意線程供其使用,不過最好遵循最佳實踐。

具體代碼導讀

iOS Android平臺可以參考Flutter Engine源碼:

Dart isolate機制

isolate定義

isolate是Dart對actor并發模式的實現。運行中的Dart程序由一個或多個actor組成,這些actor也就是Dart概念里面的isolate。isolate是有自己的內存和單線程控制的運行實體。isolate本身的意思是“隔離”,因為isolate之間的內存在邏輯上是隔離的。isolate中的代碼是按順序執行的,任何Dart程序的并發都是運行多個isolate的結果。因為Dart沒有共享內存的并發,沒有競爭的可能性所以不需要鎖,也就不用擔心死鎖的問題。

isolate之間的通信

由于isolate之間沒有共享內存,所以他們之間的通信唯一方式只能是通過Port進行,而且Dart中的消息傳遞總是異步的。

isolate與普通線程的區別

我們可以看到isolate神似Thread,但實際上兩者有本質的區別。操作系統內的線程之間是可以有共享內存的而isolate沒有,這是最為關鍵的區別。

isolate實現簡述

我們可以閱讀Dart源碼里面的isolate.cc文件看看isolate的具體實現。我們可以看到在isolate創建的時候有以下幾個主要步驟:

  • 初始化isolate數據結構
  • 初始化堆內存(Heap)
  • 進入新創建的isolate,使用跟isolate一對一的線程運行isolate
  • 配置Port
  • 配置消息處理機制(Message Handler)
  • 配置Debugger,如果有必要的話
  • 將isolate注冊到全局監控器(Monitor)

我們看看isolate開始運行的主要代碼:

我們可以看到Dart本身抽象了isolate和thread,實際上底層還是使用操作系統的提供的OSThread。

Flutter Engine Runners與Dart Isolate

有朋友看到這里可能會問既然Flutter Engine有自己的Runner,那為何還要Dart的Isolate呢,他們之間又是什么關系呢?

那我們還要從Runner具體的實現說起,Runner是一個抽象概念,我們可以往Runner里面提交任務,任務被Runner放到它所在的線程去執行,這跟iOS GCD的執行隊列很像。我們查看iOS Runner的實現實際上里面是一個loop,這個loop就是CFRunloop,在iOS平臺上Runner具體實現就是CFRunloop。被提交的任務被放到CFRunloop去執行。

Dart的Isolate是Dart虛擬機自己管理的,Flutter Engine無法直接訪問。Root Isolate通過Dart的C++調用能力把UI渲染相關的任務提交到UI Runner執行這樣就可以跟Flutter Engine相關模塊進行交互,Flutter UI相關的任務也被提交到UI Runner也可以相應的給Isolate一些事件通知,UI Runner同時也處理來自App方面Native Plugin的任務。

所以簡單來說Dart isolate跟Flutter Runner是相互獨立的,他們通過任務調度機制相互協作。

踩坑血淚史

理解Flutter Engine的原理以及Dart虛擬機的異步實現,讓我們避免采坑,更加靈活高效地進行開發。在項目應用過程我們踩過不少坑,在采坑和填坑的過程中不斷學習。這里我簡單聊其中一個具體的案例:當時我們需要把Native加載好圖片數據注冊到Engine里面去以便生成Texture渲染,使用完資源我們需要將其移除,看起來非常清晰的邏輯竟然造成了野指針問題。后來排查到注冊的時候在一個子線程進行而移除卻在Platform線程進行,在弄清楚線程結構以后問題也就迎刃而解。

結語

本文我們主要討論了Flutter引擎層面的線程配置管理以及Dart本身isolate的機制。在深入了解Flutter線程機制以后,我們在開發過程當中能夠更加得心應手。在理解Flutter設計的過程中,我們得到啟發如何去設計類似應用內的線程結構。

目前我們在探索單個Flutter Engine以組件的方式啟動,多個Flutter Engine實例同時存在通過Port來進行通信的可能方案。歡迎感興趣的朋友一起交流!


參考資料:

https://github.com/flutter/flutter

https://github.com/flutter/engine

https://flutter.io/

https://www.dartlang.org/

《Dart編程語言》

?

每天一篇技術文章,

看不過癮?

關注“阿里巴巴機器智能”微信公眾號

發現更多AI干貨。

總結

以上是生活随笔為你收集整理的聊一聊Flutter Engine线程管理与Dart Isolate机制的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。