構建我們 Python 程式碼庫的依賴關係圖
引言
秉承高頻交易的傳統,Hudson River Trading (HRT) 快速發展。與工程中的任何指標一樣,速度也有其弊端。在過去的五年裡,由於注重“足夠好”而非“完美”的工程文化,鼓勵團隊之間程式碼共享的協作工作環境,以及加速增長期,HRT 以研究為導向的 Python 程式碼庫在規模和互聯性方面呈指數級增長。隨著我們的 Python 程式碼庫增長到數百萬行,匯入時間增加了十倍,程式碼更改測試成本更高,lint 時間遠遠超出了實用範圍——我們正在經歷程式碼“纏結”的影響。
纏結
程式碼“纏結”是 HRT 員工借鑑 Dropbox 關於其 Python 程式碼庫的出版物中對同一問題的描述而來的一個概念。當代碼的依賴關係圖有許多重疊的迴圈,並且程式碼庫中不相關的部分透過間接和不直觀的匯入路徑耦合在一起時,我們稱之為“纏結”。纏結在任何大型程式碼庫中(包括其他語言)都可能是一個問題!
根據我們的經驗,纏結會影響執行時匯入和靜態分析(例如 mypy)的效能,並導致緊密的耦合,從而降低可靠性。在這些問題中,我們的使用者認為執行時匯入開銷是最大的問題,因為它會減慢開發迭代迴圈並浪費資料中心的 CPU 時間。這可能對 HRT 來說比大多數其他 Python 公司更成問題,因為短壽命的 Python 程序在我們計算工作負載中佔了相當大的比例。
纏結的負面影響會迅速增加——幾個錯誤的匯入就可能突然將數百個模組耦合在一起。匯入開銷的影響因纏結而放大,因為匯入迴圈中的任何模組最終都會傳遞性地匯入該迴圈中的所有模組(及其依賴項)。
雖然有些匯入速度很快,但在許多情況下會產生顯著的開銷。開銷悄悄進入的一種常見方式是透過檔案系統訪問——例如,現在已棄用的 pkg_resources 模組會爬取檔案系統以查詢資源。當在我們的網路檔案系統上操作時,此過程變得特別有問題。另一個計算開銷來源是載入龐大、單一的 C 擴充套件,例如 pandas 和 NumPy 等軟體包,甚至專有擴充套件。此外,我們的一些純 Python 模組會產生一系列耗時的靜態初始化步驟,例如檢測環境特性或處理類或回撥的動態註冊。
單獨來看,這些都引入了可管理的匯入工作負載;然而,在我們程式碼庫最纏結的部分,複合效應可能導致大多數程式的匯入時間超過 30 秒。這種開銷減慢了開發迭代迴圈,並浪費了我們分散式計算環境中的 CPU 時間。
依賴管理
總的來說,我們解決纏結問題的方法是建立並維護一個分層架構,其中較低層的模組不從較高層的模組匯入。建立適當的分層有助於呼叫者只匯入他們需要的東西。
理想情況下,我們的依賴關係圖應該類似於有向無環圖,其中模組按其分配的層進行拓撲排序。然而,在實踐中,只要迴圈相對較小幷包含在一個(子)包中,一些迴圈是可以接受的。
過渡到更好的依賴管理範例需要識別當前纏結的原因,重構程式碼庫以重新組織依賴關係,並實施依賴關係驗證以避免未來的迴歸。所有這些工作都必須在不暫停程式碼庫開發的情況下完成!
纏結工具:理解纏結
一旦我們瞭解到纏結是我們許多開發人員體驗問題的根源,我們便著手構建一個分析程式碼庫依賴關係圖的工具包——Tangle Tools。Tangle Tools 分析 Python 原始碼以生成整個程式碼庫的依賴關係圖(節點對應模組,邊對應匯入)。然後,我們的使用者可以利用命令列和瀏覽器介面來發現、導航和重構依賴關係。
典型的解纏結工作流包括:
-
查詢不需要的傳遞依賴
-
從源頭追蹤到不需要的依賴的匯入路徑
-
計算源和依賴之間的流量網路
-
識別哪些邊在移除後會減少流量
-
重構匯入以斷開源和依賴的連線
-
利用程式碼轉換自動化常見的重構(例如將符號移動到新模組並更新現有引用)
-
實施依賴驗證以避免迴歸
-
使用者編寫依賴規則來約束其模組的依賴關係
-
這些規則在我們的持續整合管道中進行檢查

所有這些如果不是廣泛使用開源庫,都是不可能實現的!我們使用 Python 內建的 ast 庫來解析我們的 Python 原始碼以獲取匯入。這項解析工作透過 stdlib 強大的 concurrent.futures 模組並行化,使我們能夠快速處理數千個模組。在底層,我們使用 networkx 的有向圖資料結構和豐富的圖演算法庫——我們發現流演算法特別有用。最後,我們使用 libcst 庫執行自動化原始碼重構,編寫為具體語法樹的轉換。
結論
透過開發這些依賴管理和重構工作流,我們在解纏結方面取得了顯著進展。以前,查詢匯入依賴關係是一個緩慢的手動過程,重構依賴關係則是一場打地鼠遊戲。現在,我們可以導航完整的依賴關係圖,並找到高效的重構方法,解決纏結的根本原因。
認識作者
George Farcasiu - 核心開發人員
- George Farcasiu 參與了 HRT Python 生態系統中的一系列專案,擔任 Python 靜態分析和依賴管理工具的建立者、分散式計算框架和環境的貢獻者以及構建/測試/持續整合開發工具的維護者。
Noah Kim - 核心開發人員
- Noah Kim 主要關注 HRT 對 CPython 直譯器的使用。他還是 Tangle Tools 的現任維護者,該工具是改善公司 Python 包生態系統更廣泛努力的一部分。
Jacob Brugh - 核心開發人員
- Jacob Brugh 最近的關注領域包括改進 HRT 用於我們 C++ 交易庫的 Python 繫結程式碼的效能,以及開發內部工具,使我們能夠大規模執行高效的靜態分析。
Jiahao Li - 核心開發人員
- Jiahao Li 參與了涉及分散式計算叢集和構建/測試平臺的各種專案。最近的專案包括徹底改革 HRT 的測試環境,以提供依賴跟蹤和更智慧的測試選擇。
