BookinglyTech News
Software

PyArrow y el cero copias: cómo Arrow comparte memoria entre procesos

Arrow define cómo ordenar datos en memoria por columnas para que librerías de un mismo proceso los compartan sin copiar. Te contamos qué hace posible el 'cero copias'.

3 min de lecturaDev.to0 vistas

Apache Arrow se ha convertido en el pegamento que une pandas, DuckDB, Polars y PySpark sin el coste de las conversiones tradicionales. Su éxito no es casual: se basa en un diseño de memoria columnar que permite a dos librerías del mismo proceso compartir buffers sin copiar nada. Esto no es marketing: es un mecanismo concreto definido en la interfaz C de Arrow, y merece la pena entenderlo para sacarle partido.

Qué es Arrow y qué lo diferencia de Parquet

Partamos de un error común: Arrow no es un formato de archivo. Parquet define cómo se ordenan los datos en disco, con compresión y codificación para ocupar poco. Eso obliga a decodificarlo cada vez que se quiere operar sobre él. Arrow, en cambio, define el diseño en memoria, ya decodificado y listo para que la CPU lo procese. Se sacrifica compacidad por computabilidad directa. Por eso, cuando dos herramientas intercambian Arrow, no hay una etapa de decodificación de por medio: los datos son directamente operables.

La clave está en la disposición de los buffers. Una lista Python de cadenas o un array de NumPy con dtype=object es en realidad un array de punteros; cada valor vive en una posición arbitraria de la memoria. Arrow representa las mismas tres cadenas con tres buffers contiguos: un bitmap de validez que marca nulos, un array de offsets que indica dónde empieza y termina cada valor, y un buffer de bytes con el contenido. Así se eliminan los punteros dispersos y los headers de objeto de Python, y la memoria se vuelve homogénea y vectorizable.

El mecanismo real del cero copias

Esa homogeneidad es la que hace posible el cero copias. La interfaz C Data de Arrow define un par de estructuras (ArrowArray y ArrowSchema) que cualquier proyecto puede copiar en su propio árbol de fuentes sin ninguna dependencia externa. Dos programas compilados por separado, en lenguajes distintos, pueden intercambiar un array Arrow en runtime con solo acordar el layout de esas estructuras y pasarse un puntero. Python lo hace a través de ctypes o cffi.

Comparemos con pickle, JSON o protobuf: todos recorren la estructura fuente, la transforman a otra representación de bytes y la reconstruyen en el destino. Ese coste es proporcional al tamaño de los datos. La interfaz C de Arrow lo evita por completo cuando la transferencia es dentro del mismo proceso: no hay conversión, solo un acuerdo para mirar a los mismos buffers. La limitación es que el puntero solo tiene sentido si ambas partes acceden a la misma memoria; si los datos deben salir del proceso, se usa el formato IPC de Arrow, pero incluso esa serialización es mínima comparada con la de pickle.

Por qué importa

Para quien trabaja con datos en Python, Arrow ha dejado de ser un detalle técnico para convertirse en la infraestructura que evita que cada salto entre librerías se convierta en un cuello de botella. Saber exactamente qué hace que el cero copias sea real ayuda a decidir cuándo merece la pena usarlo y a diagnosticar esos casos donde, por más que se hable de cero copias, aparece una conversión inesperada. La respuesta, casi siempre, está en si las dos partes hablan el mismo dialecto de Arrow o si una de ellas está serializando por detrás.