Apache Arrow C 資料介面介紹
已發布 2020年5月3日
作者 Antoine Pitrou (apitrou)
Apache Arrow 包含跨語言、獨立於平台的記憶體內欄狀格式,允許異質執行階段和應用程式之間的零複製資料共享和傳輸。
使用 Arrow 欄狀格式最簡單的方式一直以來都是依賴 Apache Arrow 社群開發的具體實作。到目前為止,專案程式碼庫包含 11 種不同程式語言的函式庫,未來可能會擴展到包含更多語言。
然而,某些專案可能希望匯入和匯出 Arrow 欄狀格式,而無需承擔新的函式庫依賴性,例如 Arrow C++ 函式庫。 因此,我們設計了一種替代方案,在 C 語言層級交換資料,並符合簡單的資料定義。 C 資料介面不帶任何依賴性,除了使用它的二進制檔案之間共享的 C ABI。 C ABI 是平台廣泛的標準,所有產生二進制檔案的編譯器都必須遵守,並且非常穩定,確保函式庫和可執行二進制檔案的可移植性。 兩個利用 C 資料介面定義的 C 結構的函式庫可以在執行階段進行零複製資料傳輸,而無需任何建置時或連結時的依賴性要求。
了解 C 資料介面的最佳方式是閱讀規格。 然而,我們將快速瀏覽其優點。
兩個簡單的結構定義
為了在 C 或 C++ 層級與 C 資料介面互動,您唯一需要在程式碼中包含的是兩個結構類型宣告(以及一些用於常數值的 #define
)。 這些宣告僅依賴標準 C 類型,並且可以簡單地貼到標頭檔中。 其他語言只要提供外部函式介面層也可以參與; 大多數現代語言都是這種情況,例如 Python(使用 ctypes
或 cffi
)、Julia、Rust、Go 等。
零複製資料共享
C 資料介面透過記憶體指標傳遞 Arrow 資料緩衝區。 因此,透過建構,它允許您在一個執行階段與另一個執行階段之間共享資料,而無需複製它。 由於資料採用標準的 Arrow 記憶體內格式,因此其佈局是明確定義且明確的。
此設計也將 C 資料介面限制為程序內資料共享。 對於跨程序通訊,我們建議使用 Arrow IPC 格式。
減少序列化
C 資料介面與在 C 或 C++ 中表達類似 Arrow 資料的自然方式非常接近。 只有兩個方面涉及非平凡的序列化
- 資料類型的編碼,使用非常簡單的基於字串的語言
- 可選元數據的編碼,使用非常簡單的長度前綴格式
分離的類型和資料表示
對於產生單一資料類型多個資料實例的應用程式(例如,作為記錄批次的串流),從其字串編碼重複重建資料類型將代表不必要的開銷。 為了解決此使用案例,C 資料介面定義了兩個獨立的結構:一個表示資料類型(和可選元數據),另一個表示一段資料。
生命週期處理
異質執行階段之間資料共享的一個常見困難是正確處理資料的生命週期。 C 資料介面允許生產者透過釋放回呼來定義自己的記憶體管理方案。 這是一個簡單的函式指標,消費者在使用完資料後會呼叫它。 例如,當用作生產者時,Arrow C++ 函式庫會傳遞一個釋放回呼,該回呼只會遞減 shared_ptr
的參考計數。
應用:在 R 和 Python 之間傳遞資料
R 和 Python Arrow 函式庫都基於 Arrow C++ 函式庫,但是它們各自的工具鏈(由 R 和 Python 封裝標準規定)在 ABI 上不相容。 因此,不可能在 R 和 Python 綁定之間直接在 C++ 層級傳遞資料。
使用 C 資料介面,我們規避了此限制,並在 R 和 Python 之間提供了零複製資料共享 API。 它基於 R reticulate
函式庫。
這是一個混合 R 和 Python 函式庫調用的範例會話
library(arrow)
library(reticulate)
use_virtualenv("arrow")
pa <- import("pyarrow")
# Create an array in PyArrow
a <- pa$array(c(1, 2, 3))
a
## Array
## <double>
## [
## 1,
## 2,
## 3
## ]
# Apply R methods on the PyArrow-created array:
a[a > 1]
## Array
## <double>
## [
## 2,
## 3
## ]
# Create an array in R and pass it to PyArrow
b <- Array$create(c(5, 6, 7))
a_and_b <- pa$concat_arrays(r_to_py(list(a, b)))
a_and_b
## Array
## <double>
## [
## 1,
## 2,
## 3,
## 5,
## 6,
## 7
## ]