載入速度提升 15%,關於 Python 啟動加速探索與實踐的解析 | 龍蜥技術

OpenAnolis小助手發表於2022-12-22

編者按:在剛剛結束的 PyCon China 2022 大會上,龍蜥社群開發者嚴懿宸分享了主題為《Python 啟動加速的探索與實踐》的技術演講。本次演講,作者將從 CPython 社群相關工作、本方案的設計及實現,以及業務層面的整合等方面進行介紹。

以下為本次演講內容:

載入速度提升 15%,關於 Python 啟動加速探索與實踐的解析 | 龍蜥技術

一、Python 啟動速度簡析

首先從一個 Python 3 中空直譯器啟動時間的好事分析開始。我們可以看到,主要的耗時都和 Python 包載入有關。

載入速度提升 15%,關於 Python 啟動加速探索與實踐的解析 | 龍蜥技術

其中,CPU 時間中包載入佔據了 30% 左右的時間;而 37% 的等待時間中,磁碟 IO 等花費的時間也和包載入有較大的關聯。

熟悉 Python 機制的朋友大概知道,Python 中載入一個包首先會搜尋對應的 pyc 檔案,這是一種序列化的位元組碼格式。找到之後會對其進行反序列化,並執行其中的程式碼。如對應的 pyc 檔案不存在,會重新編譯 py 檔案得到位元組碼,並序列化為 pyc 檔案持久化儲存。我們最佳化的主要目標主要集中在載入包這個過程,希望能夠至少免去每次查詢、讀取、反序列化的開銷。

載入速度提升 15%,關於 Python 啟動加速探索與實踐的解析 | 龍蜥技術

以 Python3.10 為例,這裡是使用 python 直譯器啟動一個空語句的所需時間,同時使用了 -Ximporttime 列印出過程中載入每一個包的耗時。可以粗略地看到,包載入時間大約佔了總時間的 30% 左右。我們發現這種情況和 Java 虛擬機器類似。在 Java 中,Java 會首先將 Java 原始碼編譯為 Java 位元組碼,隨後由 Java 命令執行。

我們知道 Java 的優勢並不包括啟動速度,這種流程也是原因之一。那麼 Java 如何部分解決這個問題呢?

二、PyCDS (程式碼物件共享)設計與實現

載入速度提升 15%,關於 Python 啟動加速探索與實踐的解析 | 龍蜥技術

Java 中有一個叫做 CDS/AppCDS 的機制,透過將 Java 位元組碼和一些輔助資料持久化儲存,在後續啟動時使用 mmap 載入,節約了磁碟 IO 和解析驗證 class 檔案的開銷。

很自然的想法是,如果我們希望在 Python 中使用類似的技術,目標應該是 Python 位元組碼。

載入速度提升 15%,關於 Python 啟動加速探索與實踐的解析 | 龍蜥技術

Python 預設從 py 檔案匯入模組的邏輯如上圖左邊所示,首先根據制定的名字獲取對應的規則,隨後嘗試尋找 pyc 檔案或重新編譯。最後,使用 exec 命令利用程式碼和一個空 dict 來建立模組,並加入 runtime。

我們做的事情可以簡化為右側邏輯。同樣根據包名,嘗試從 mmap 中載入。如果成功,那麼同樣的 codeobject 也可以用於初始化。

這樣做有什麼直接的障礙?

可以看到,Python 中程式碼物件的 C 資料結構大致如圖,包括 consts、string、bytes 等 Python 資料型別。

載入速度提升 15%,關於 Python 啟動加速探索與實踐的解析 | 龍蜥技術

以使用到的 codeobject 作為 root,將涉及的資料序列化儲存到記憶體對映中。

在這一步,最直接的問題是記憶體隨機化機制。在處理 code object 中的 Python 物件時,每個 Python 物件頭中都儲存著指向當前程式中對應型別資訊的指標。Runtime 透過這個指標判斷該物件在 Python 中的型別。

以 PyCode_Type 為例,如果不做處理,這裡會丟失型別資訊(紅色 offset)。

為了解決這個問題,在我們建立的映象檔案中會儲存涉及的物件指標。在載入時動態 patch 相關的指標。

在整個過程中涉及的 Python 型別包括:

  1. 常量(bool/None/ellipsis)

  2. 字面量(float/complex)

  3. 需要額外分配的變數(long/bytes/str)

  4. container(tuple/frozenset)

對於常量和字面量,在記憶體對映中分配好空間後直接賦值即可儲存;對於後兩種,需要模擬 Python 中變數初始化的邏輯,建立合適的記憶體大小並寫入對應位置。同時,對於非常量的型別,還需要對記憶體對映中的引用計數額外賦值,防止意外觸發 Python 中的回收。

以上就是本專案的大致內容,另外關於專案的具體用法請前往 PyCDS 專案主頁或我們在 龍蜥實驗室上的課程檢視,連結見下:

龍蜥實驗室課程:lab.openanolis.cn/#/apply/chapters?courseId=117

PyCDS 主頁:github.com/alibaba/code-data-share-for-python



—— 完 ——


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70004278/viewspace-2929129/,如需轉載,請註明出處,否則將追究法律責任。

相關文章