Alcinoe 是適用於 Delphi 與 C++Builder 的開源元件庫,由 Zeus64 於 GitHub 上維護。它補足了 VCL 與 FireMonkey RTL 留給第三方的功能區塊:硬體加速 (GPU) 的影片播放器、WebRTC 封裝、原生 iOS 與 Android 編輯控制項、雙模式 JSON/BSON 解析器、具備連線池的 MongoDB 用戶端、ImageMagick 封裝,以及一系列完全避開內建渲染管線的 FireMonkey 控制項。該函式庫在 Rio (10.3.3) 與 Sydney (10.4.2) 建立起口碑,此後便持續跟進每個 Embarcadero 發行版本。截至撰稿時,它完全相容於 Delphi 11.1 Alexandria 與 Delphi Athens 12.3
將 Alcinoe 匯入專案
安裝方式取決於一個問題:您是否需要設計階段 (design-time) 支援 Alcinoe 的視覺控制項?如果不需要,請直接略過 BPL。將 {alcinoe_rootdir}\source 加入專案的函式庫搜尋路徑即可。每個非視覺化元件(包含解析器、資料庫用戶端與字串工具)都能從原始碼編譯,無須註冊任何項目
當您需要設計階段支援時,步驟會稍微長一些。在 Delphi IDE 中開啟 Component > Install Packages,瀏覽至符合您版本的 BPL(例如 {alcinoe_rootdir}\lib\bpl\alcinoe\Win32\alexandria\Alcinoe_alexandria.bpl),安裝它,接著仍須將 {alcinoe_rootdir}\source 加入搜尋路徑。BPL 負責註冊元件;而原始碼目錄則是讓編譯器在編譯您的專案時能找到相關檔案
Alcinoe 提供了可選的 Embarcadero RTL 原始碼修補程式 (patches)。如果您需要它們,請導覽至 {alcinoe_rootdir}\embarcadero\,選擇對應版本的子目錄,然後執行 update.bat。該指令碼預設 PATH 中已包含 GIT,並假定預設的 Embarcadero 安裝位置。它會擷取原始 RTL 原始碼並套用修補程式。完成後,將該已修補的原始碼目錄加入您的專案搜尋路徑中,讓編譯器能優先於 Embarcadero 安裝目錄中的唯讀備份採用它。這些都不是入門必備的步驟;只有當您遇到修補程式所解決的錯誤時,這才重要
Android 與 D8 去語法糖 (desugaring) 代理
幾個 Alcinoe 元件(WebRTC、基於 ExoPlayer 的影片)依賴使用 Java 8 語言功能的 Java 函式庫。隨附於較舊 Delphi 版本的 Android 工具鏈使用 dx.bat 進行 DEX 轉換,該轉換無法在低於 API 層級 26 的環境下處理那些位元組碼 (bytecodes)。解決方法是去語法糖,當直接呼叫時 D8 會自動處理。Alcinoe 在 {alcinoe_rootdir}\tools\D8Proxy\dx.bat 提供了一個代理指令碼,將來自 Delphi 建置系統的呼叫轉發給 D8,讓去語法糖的過程變得透明。將 Android SDK build-tools 目錄(通常是 C:\SDKs\android\build-tools\30.0.3\)中的原始 dx.bat 替換為此代理。Embarcadero 在 RSP-24155 中追蹤了根本問題;較新版本的 SDK 工具已直接解決此問題,因此請檢查您目前的工具鏈是否仍需要此替代方案
FireMonkey 渲染問題與 Alcinoe 的解答
FireMonkey 預設的繪製週期在大量捲動的 UI 中會成為效能瓶頸。單一帶有圓角的 TRectangle 重新繪製約需 3 毫秒,因為內建實作會在每一影格上重新計算路徑。當有 20 個這類控制項可見時,每一影格的處理時間就累加到 60 毫秒,這會將有效畫面更新率限制在遠低於流暢捲動標準的臨界值
Alcinoe 藉由為每個控制項提供駐留於 GPU 的緩衝區來解決此問題。第一次繪製會將控制項渲染至儲存於 GPU 記憶體中的 TTexture。後續的重新繪製會區塊傳輸 (blit) 該紋理,而不是重新執行繪製演算法。在相同的圓角矩形上測得的結果從約 3 毫秒下降至約 0.1 毫秒。除了緩衝之外,Alcinoe 也以原生 Android 和 iOS 繪圖 API 取代了基本形狀的 OpenGL 路徑繪製,避開了與 Form.Quality 相關的品質/效能權衡。相關控制項包含 TALRectangle、TALCircle 以及一組改進的版面配置容器(包含 ScrollBox 與 TabControl)
TALJsonDocument:集 DOM 與 SAX 於一體的型別
TALJsonDocument 是 Alcinoe 的 JSON 與 BSON 解析器。它支援兩種走訪模式。DOM 模式會建立記憶體內的物件樹,提供對任何節點的隨機存取,代價是與文件大小成正比的記憶體消耗。SAX 模式在解析器讀取每個符記 (token) 時觸發事件,而不保留任何樹狀結構,當您需要過濾大型文件且只保留少數值時,這是正確的選擇。Delphi 中的 DOM 解析器(DBXJSON、SuperObject 等)在處理相同內容時,通常比 SAX 方法慢三到五倍,因為每個節點的配置除了實際的解析工作之外,還帶有物件建立的負擔
該型別遵循與 TALXMLDocument 相同的節點導覽模式。最小的 DOM 讀取如下所示:
MyJsonDoc.LoadFromJSON(AJsonStr, False {dom mode});
MyJsonDoc.ParseOptions := [poAllowComments];
// read scalar values
ShowMessage(MyJsonDoc.ChildNodes['name'].ChildNodes['first'].Text);
ShowMessage(IntToStr(MyJsonDoc.ChildNodes['_id'].Int32));
// iterate an array
for I := 0 to MyJsonDoc.ChildNodes['contribs'].ChildNodes.Count - 1 do
Writeln(MyJsonDoc.ChildNodes['contribs'].ChildNodes[I].Text);
對於 SAX 模式,請在呼叫 LoadFromJSON 之前將一個匿名程序指派給 OnParseText,並將第二個引數設定為 True。回呼函數 (callback) 會接收節點路徑、名稱、值以及識別 JSON 型別(字串、整數、浮點數、布林值等)的 TALJSONNodeSubType。該模式不會為節點產生堆積配置 (heap allocations),因此可以擴展到任意大型的文件而不會超出記憶體預算
TALJsonDocument 也能原生讀取和寫入 BSON;只需將 LoadFromFile 或 SaveToFile 的 BSON 旗標傳遞為 True。第二個變體 TALJsonDocumentU 內部使用 UnicodeString (UTF-16) 而非 AnsiString (UTF-8),適用於周圍程式碼完全以 Unicode 運作的環境
MongoDB 用戶端與連線池
Alcinoe 的 MongoDB 驅動程式涵蓋了常見的查詢作業,並原生處理連線池。簡單的用戶端 TAlMongoDBClient 為每項作業開啟並關閉單一連線。連線池變體 TAlMongoDBConnectionPoolClient 則維護一組活動連線,並將池中的一個連線交給每個發出呼叫的執行緒,在呼叫完成時將其歸還。這種模型可避免多個執行緒在連線建立時互相阻擋,當背景工作執行緒同時查詢同一個資料庫時,這一點至關重要。對於固定大小集合 (capped collections) 上的可追蹤游標 (tailable cursors),TAlMongoDBTailMonitoringThread 會監視新文件並在它們抵達時觸發回呼函數,這是記錄檔串流或無需輪詢的變更通知的標準模式
其他值得了解的元件
ALVideoPlayer 將影片渲染至 TTexture 而非覆蓋視窗,因此其他 FireMonkey 控制項可以在 Z 軸順序 (Z-order) 上位於其上方。Android 後端使用 ExoPlayer,它增加了對 DASH、HLS 與 SmoothStreaming 的支援,超出了 Android 內建 MediaPlayer 處理的範圍。iOS 後端使用具有同等 HLS 支援的 AVPlayer
TALWebRTC 封裝了用於點對點音訊和影片的 WebRTC 堆疊。它不需要瀏覽器或外掛程式,連線可透過標準 ICE/STUN/TURN 協商穿越 NAT,而底層函式庫會處理這些協商
TALStringList 以與地區無關的序數比較和快速排序 (quicksort) 取代了 TStringList 基於 AnsiCompareText 的排序,在大型清單上的速度最高可快 10 倍。雜湊變體 TALHashedStringList 增加了一個內部雜湊表以達到 O(1) 的查詢速度,代價是小型清單的負擔略高。請注意,TALStringList 是 8 位元的 AnsiString 清單,而不是 Unicode 清單;它非常適合 UTF-8 為工作編碼且原始吞吐量比可識別地區的比較更重要的伺服器端程式碼
在 64 位元 Windows 上,讓許多 Alcinoe 字串常式具備速度優勢的 FastCode 傳統(大部分是手寫的 x86 組合語言)無法延續。Win64 建置會退回到 Pascal 實作,在密集使用字串的工作負載中執行速度明顯較慢。在致力於字串吞吐量成為瓶頸的 64 位元建置之前,demo\ALStringBenchMark 專案能讓您在自己的硬體上測量這種差距
完整原始碼位於 github.com/Zeus64/alcinoe