- 適用於 JDK 23 的 GraalVM (最新)
- 適用於 JDK 24 的 GraalVM (搶先體驗)
- 適用於 JDK 21 的 GraalVM
- 適用於 JDK 17 的 GraalVM
- 封存
- 開發版本
Python 效能
執行效能 #
GraalPy 使用 GraalVM 最先進的即時 (JIT) 編譯器。經過 JIT 編譯後,GraalPy 在官方 Python 效能基準測試套件上的執行速度比 CPython 快約 4 倍。
這些基準測試可以透過安裝 pyperformance
套件並在 CPython 和 GraalPy 上分別呼叫 pyperformance run
來執行。為了取得 Jython 的數字,我們調整了執行工具和基準測試,因為 Jython 中缺少 Python 3 支援。然後,透過取得有效基準測試的成對交集並計算幾何平均值來計算加速比。
在沒有 JIT 編譯器的情況下,GraalPy 目前執行純 Python 程式碼的速度比 CPython 慢約 4 倍。這表示在 Oracle JDK 或 OpenJDK 上執行時,執行時間非常短的腳本或在沒有 Graal 編譯器的情況下執行的腳本預期會較慢。
來自機器學習或資料科學生態系統的許多 Python 套件都包含 C 擴充程式碼。此程式碼從 GraalPy 的 JIT 編譯獲益甚少,並且由於必須在 GraalPy 上模擬 CPython 實作細節而受到影響。當涉及許多 C 擴充程式碼時,效能可能會因原生程式碼和 Python 程式碼的特定互動而有很大差異。
程式碼載入效能和佔用空間 #
剖析 Python 程式碼需要時間,因此當使用 GraalPy 在 Python 中嵌入其他語言時,請參考有關 跨多個內容快取程式碼的嵌入 Graal 語言的一般建議。此外,某些 Python 程式庫在可以執行任何工作之前,需要在啟動時載入大量程式碼。由於 Python 語言的設計,無法進行增量剖析,對於某些腳本而言,剖析器可能佔用運行時間和記憶體的很大一部分。為了緩解此問題,如果已設定適當的檔案系統存取,GraalPy 可以將剖析期間產生的位元組碼快取在 .pyc 檔案中。
建立和管理 .pyc 檔案 #
當與對應的 .py 檔案相符的 .pyc 檔案無效或不存在時,GraalPy 會自動建立 .pyc 檔案。
當 GraalPy 在執行期間第一次匯入 Python 原始檔 (模組) 時,它會自動建立對應的 .pyc 檔案。如果 GraalPy 再次匯入相同的模組,則會使用現有的 .pyc 檔案。這表示對於尚未執行 (匯入) 的原始檔,沒有 .pyc 檔案。GraalPy 完全透過 FileSystem API 建立 .pyc 檔案,因此具有嵌入式 Python 程式碼的 Java 應用程式可以管理檔案系統存取。
注意:GraalPy 永遠不會刪除 .pyc 檔案。
每次 GraalPy 後續執行腳本時,它都會重複使用現有的 .pyc 檔案,或建立新的檔案。如果原始原始檔的時間戳記或雜湊碼已變更,GraalPy 會重新建立 .pyc 檔案。GraalPy 僅透過呼叫 source.hashCode()
,根據 Python 原始檔產生雜湊碼,這是在原始檔位元組陣列上的 JDK 雜湊碼,使用 java.util.Arrays.hashCode(byte[])
計算。
如果 Python 剖析器中的 magic number 已變更,GraalPy 也會重新建立 .pyc 檔案。magic number 是硬式編碼在 Python 原始碼中,並且無法由使用者變更 (除非該使用者有權存取 Python 的位元組碼)。
當位元組碼格式變更時,GraalPy 的開發人員會變更 magic number。這是一個實作細節,因此 magic number 不必對應到 GraalPy 的版本 (如 CPython 中所示)。pyc
的 magic number 是實際執行中的 Python 執行期 Java 程式碼的函數。magic number 的變更會在版本資訊中傳達,以便開發人員或系統管理員可以在升級時刪除舊的 .pyc 檔案。
請注意,如果您使用 .pyc 檔案,則至少在切換版本或修改原始原始碼檔案時,必須允許 GraalPy 具有寫入權限。否則,將無法重新產生原始碼檔案,並且每次匯入都會有存取每個舊 .pyc 檔案、剖析程式碼、序列化程式碼,以及嘗試 (和失敗) 寫出新 .pyc 檔案的額外負擔。
GraalPy 為 .pyc 檔案建立下列目錄結構
top_directory/
__pycache__/
sourceA.graalpy.pyc
sourceB.graalpy.pyc
sourceA.py
sourceB.py
sub_directory/
__pycache__/
sourceX.graalpy.pyc
sourceX.py
依預設,GraalPy 在與原始碼檔案相同的目錄層級上建立 __pycache__ 目錄,並且在此目錄中儲存來自相同目錄的所有 .pyc 檔案。此目錄可能會儲存使用不同版本的 Python (包括例如 CPython) 建立的 .pyc 檔案,因此使用者可能會看到以 .cpython3-6.pyc 結尾的檔案,例如。
.pyc 檔案主要由 GraalPy 自動管理,其方式與 CPython 相容。GraalPy 提供與 CPython 類似的選項來指定 .pyc 檔案的位置,以及是否應寫入它們,並且這兩個選項都可以由客體程式碼變更。
.pyc 檔案的建立可以透過與 CPython 相同的方式來控制
- GraalPy 啟動器 (
graalpy
) 會讀取PYTHONDONTWRITEBYTECODE
環境變數。如果將此變數設定為非空字串,則 Python 在匯入模組時不會嘗試建立 .pyc 檔案。 - 如果給定啟動器命令列選項
-B
,則其效果與上述相同。 - 客體語言程式碼可以在執行階段變更內建模組
sys
的屬性dont_write_bytecode
,以變更後續匯入的行為。 - GraalPy 啟動器會讀取
PYTHONPYCACHEPREFIX
環境變數。如果已設定,則它會在前置詞指定的路徑建立 __pycache__ 目錄,並建立原始碼樹狀結構的鏡像,以隨需儲存 .pyc 檔案。 - 客體語言程式碼可以在執行階段變更
sys
模組的屬性pycache_prefix
,以變更後續匯入的位置。
因為開發人員無法使用環境變數或 CPython 選項將這些選項傳達給 GraalPy,所以這些選項會以語言選項的形式提供
python.DontWriteBytecodeFlag
- 相當於-B
或PYTHONDONTWRITEBYTECODE
python.PyCachePrefix
- 相當於PYTHONPYCACHEPREFIX
請注意,Python 內容預設不會啟用寫入 .pyc 檔案。GraalPy 啟動器預設會啟用它,但如果要在嵌入使用案例中使用,則應注意確保正確管理 __pycache__ 位置,並且該位置中的檔案會受到保護,不會以與衍生它們的原始碼檔案 (.py) 相同的方式受到操作。
另請注意,若要將應用程式來源升級至 Oracle GraalPy,開發人員必須根據需要移除舊的 .pyc 檔案。
安全性考量 #
GraalPy 會透過 FileSystem API 執行所有檔案作業 (取得資料、時間戳記和寫入 .pyc 檔案)。開發人員可以透過自訂 (例如唯讀) FileSystem
實作來修改所有這些作業。開發人員也可以透過停用 GraalPy 的 I/O 權限,有效地停用 .pyc 檔案的建立。
如果 .pyc 檔案不可讀,則其位置不可寫入。如果 .pyc 檔案的序列化資料或 magic number 以任何方式損毀,則還原序列化會失敗,並且 GraalPy 會再次剖析 .py 原始碼檔案。這僅對模組的剖析造成輕微的效能損失,對於大多數應用程式來說,這應該不顯著 (前提是應用程式除了載入 Python 程式碼之外還執行實際工作)。