Learning Platform
Глоссарий Troubleshooting
Урок 11.04 · 22 мин
Средний
ArrowC-Data-InterfacePEP-749ABIinterchange-protocolzero-copycross-libraryArrowSchemaArrowArraycross-course

Arrow C Data Interface — DataFrame interchange protocol

М10 урок 03 показал что Arrow — universal columnar format и pandas / Polars / DuckDB / Spark все используют те же memory buffers. Как это работает на практике? Через Arrow C Data Interface — ABI-stable C struct + PEP 749 (Python DataFrame interchange protocol). Этот урок объясняет mechanism zero-copy interop через language boundaries.

В этом уроке:

  1. Why universal Arrow representation matters — production pipelines combine multiple libraries.
  2. Arrow C Data Interface — ABI-stable C struct + reference counting.
  3. PEP 749 — Python DataFrame interchange protocol (in progress).
  4. Cross-library zero-copy demo — pandas ↔ Polars ↔ DuckDB ↔ Arrow Table.
  5. Cross-course — Storage Formats M07/03 IPC format + DataFusion M01/02 Arrow foundation.

Why universal Arrow representation matters

Production DE pipeline часто комбинирует несколько библиотек:

S3 Parquet → Polars (lazy ETL) → pandas (Jupyter analysis) → DuckDB (SQL) → ClickHouse (analytics)

Без universal representation каждый handoff требует:

Polars DataFrame → polars.write_parquet() → bytes → pandas.read_parquet() → pandas DataFrame
                   ^^^^^^^^^^^^^^^^^^^^^                                    ^^^^^^^^^^^^^^^^^^^^
                   serialize CPU cost + 2x memory                            deserialize CPU cost + 2x memory

Multi-hop pipelines cost a lot of CPU и память на serialize-deserialize.

С universal Arrow representation:

Polars DataFrame ← (pointer) → Arrow C Data Interface → (pointer) → pandas DataFrame

Один и тот же memory accessed by multiple libraries — zero CPU cost, zero memory overhead. Это interchange protocol — не format на disk, а handshake между libraries в RAM.


Arrow C Data Interface — ABI-stable C struct

Arrow C Data Interface spec определяет три C struct:

struct ArrowSchema {
    // Type metadata
    const char* format;
    const char* name;
    const char* metadata;
    int64_t flags;
    int64_t n_children;
    struct ArrowSchema** children;
    struct ArrowSchema* dictionary;

    // Reference counting / cleanup
    void (*release)(struct ArrowSchema*);
    void* private_data;
};

struct ArrowArray {
    // Data buffers (validity bitmap, values, offsets)
    int64_t length;
    int64_t null_count;
    int64_t offset;
    int64_t n_buffers;
    int64_t n_children;
    const void** buffers;
    struct ArrowArray** children;
    struct ArrowArray* dictionary;

    // Reference counting / cleanup
    void (*release)(struct ArrowArray*);
    void* private_data;
};

struct ArrowDeviceArray {
    // GPU/accelerator-aware variant (for cuDF, etc.)
    struct ArrowArray array;
    int64_t device_id;
    ArrowDeviceType device_type;
    void* sync_event;
};

Ключевые свойства:

  1. ABI-stable — sizeof + layout struct гарантированы стабильны во времени. Library compiled на Arrow 5.0 читает struct из Arrow 15.0 без перекомпиляции.
  2. Language-agnostic — C struct работает в C, C++, Rust (через FFI), Python (через ctypes или cffi), R, Java (JNI). Universal handshake.
  3. Reference counting — caller получает struct + увеличивает refcount; вызывает release() при завершении. Producer manages lifecycle до последнего release.
  4. Pointer-based — buffers — указатели на existing memory; никаких копий. Producer может вернуть указатель на свой internal buffer; consumer reads без копирования.

Cite Apache Arrow Format spec — C Data Interface.


PEP 749 — Python DataFrame interchange protocol

PEP 749 (in progress, status: deferred / draft) — стандартизирует Python-level DataFrame interchange:

# Любой DataFrame-подобный объект implements `__arrow_c_stream__` или `__arrow_c_array__` dunder
class MyDataFrame:
    def __arrow_c_stream__(self, requested_schema=None):
        """Returns (Schema_capsule, Array_iterator_capsule)."""
        ...

    def __arrow_c_array__(self, requested_schema=None):
        """Returns (Schema_capsule, Array_capsule)."""
        ...

# Consumers вызывают dunder; receive C Data Interface struct (wrapped в PyCapsule)
df = some_library_dataframe
schema_capsule, array_capsule = df.__arrow_c_array__()
# convert к Arrow Table / pandas / Polars

Стандарт описывает:

  • Названия dunder methods (__arrow_c_stream__, __arrow_c_array__, __arrow_c_schema__).
  • Ожидаемый PyCapsule API + naming convention.
  • Schema negotiation (consumer может request specific types через requested_schema).

Production status:

  • pandas 2.2+ — implements producer side (DataFrame → Arrow capsule).
  • Polars 1.0+ — implements both producer + consumer.
  • PyArrow 15+ — implements full producer/consumer + schema negotiation.
  • DuckDB 0.10+ — Arrow-compatible result format.

Pre-PEP 749 existed __dataframe__ protocol (DataFrame interchange protocol — older proposal). Production today — Arrow C Data Interface через PyCapsule поверх PEP 749 path.

Cite PEP 749 — Implementing Arrow PyCapsule Interface.


Cross-library zero-copy demo

import pyarrow as pa
import pandas as pd
import polars as pl

# Build Arrow Table once
table = pa.Table.from_pylist([{'a': 1, 'b': 'x'}, {'a': 2, 'b': 'y'}])

# Zero-copy → pandas (Arrow C Data Interface через PyArrow)
df_pd = table.to_pandas(types_mapper=pd.ArrowDtype)
# pandas 2.0+ Arrow-backed dtypes — same memory accessed

# Zero-copy → Polars
df_pl = pl.from_arrow(table)
# Polars Arrow backbone — direct pointer

# Zero-copy → DuckDB
import duckdb
con = duckdb.connect()
con.register('arrow_view', table)
result = con.execute("SELECT * FROM arrow_view WHERE a > 1").arrow()
# Result back as Arrow Table — same RAM

# Round-trip pandas → Polars без serialize
arrow_from_pd = pa.Table.from_pandas(df_pd)         # zero-copy if Arrow-backed
back_to_polars = pl.from_arrow(arrow_from_pd)        # zero-copy

Implementation detail: под капотом каждый из этих converters вызывает Arrow C Data Interface dunder methods (PEP 749 path) или PyArrow native APIs. Consumer получает PyCapsule с ABI-stable struct → reads buffers → no copy.

Production rule: в multi-library pipelines избегайте pickle.dumps, df.to_csv(), df.to_json() для in-memory handoffs — используйте Arrow путь (pa.Table.from_pandas(df), pl.from_arrow(table), con.register('view', table)). Это существенно дешевле для больших данных.

Cite PyArrow docs — Pandas integration + Polars docs — Arrow integration.


Cross-course → Storage Formats M07/03 IPC + DataFusion M01/02 Arrow foundation

Storage Formats M07 arrow — Arrow on-disk + on-wire counterpart:

  • 07/03 — IPC format — Arrow IPC stream/file format spec — wire layout для cross-process zero-copy. C Data Interface работает в RAM; IPC format кодирует то же самое в bytes для disk persistence или network transfer (Flight protocol).
  • 07/05 — Flight protocol — gRPC-based Arrow data transfer protocol; production pattern для cross-server zero-copy (Spark Connect, BigQuery Storage API).

Cross-course connection: C Data Interface = in-RAM handshake; IPC format = bytes-on-wire equivalent. Same buffers, two delivery mechanisms.

DataFusion M01 arrow-foundation — DataFusion (Rust-native query engine) использует Apache Arrow как native representation:

Cross-course bridge insight: Arrow C Data Interface — glue который соединяет multi-language ecosystem. pandas (Python) → Polars (Rust внутри Python) → DuckDB (C++ внутри Python) → Spark (JVM) → DataFusion (Rust). Все читают/пишут same Arrow buffers через C Data Interface.


Что в следующем уроке

М10 урок 05 — Pyodide constraints — почему pandas / Polars / PyArrow / NumPy не запускаются в browser challenges; WASM size limits, C-extension dependencies, micropip experimental status. Объясняет decision учить эти libraries conceptually + Run-on-Your-Machine для real demos.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 4. **Apply scenario:** production DE pipeline комбинирует Polars (lazy ETL) → pandas (Jupyter analysis) → DuckDB (SQL). Без Arrow C Data Interface каждый handoff требует serialize/deserialize. Какая cost?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 7