Как стрелка apache способствует отсутствию накладных расходов при межсистемном взаимодействии?

Я был очень заинтересован в Apache Arrow в течение некоторого времени из-за обещаний «нулевое копирование чтения», «нулевое значение serde» и «отсутствие накладных расходов для межсистемной связи». Я понимаю проект (через призму pyarrow): он описывает память и формат данных, так что несколько задач могут читать это как карту сокровищ и все найти свой путь к одним и тем же данным (без копирования). Думаю, я могу увидеть, как это работает в Python / Pandas в одном процессе; довольно легко создать массив Arrow, передать его разным объектам и наблюдать за всем «нулевым копированием» в действии.

Однако, когда мы говорим о межсистемной коммуникации без накладных расходов, я почти полностью теряюсь. Например, как PySpark преобразовывает объекты Java в формат стрелки, а затем передает его в Python / Pandas? Я попытался посмотреть код здесь, но для парня, не использующего java / scala, это выглядит так, будто он преобразует искровые строки в объекты Arrow, а затем в byteArrays (строка 124), что не кажется мне нулевой копией, нулевыми накладными расходами.

Точно так же, если бы я хотел попытаться передать массив Arrow из Python / pyarrow, скажем, в Rust (используя Rust Arrow API), я не мог бы осознать, как бы я это сделал, особенно учитывая, что этот подход к вызову функции Rust из Python не соответствует Кажется, не работает с примитивами Arrow. Есть ли способ указать как Rust, так и Python на один и тот же адрес (а) памяти? Должен ли я каким-то образом отправлять данные стрелок в виде byteArray?

// lib.rs
#[macro_use]
extern crate cpython;

use cpython::{PyResult, Python};
use arrow::array::Int64Array;
use arrow::compute::array_ops::sum;

fn sum_col(_py: Python, val: Int64Array) -> PyResult<i64> {
    let total = sum(val).unwrap();
    Ok(total)
}

py_module_initializer!(rust_arrow_2, initrust_arrow_2, Pyinit_rust_arrow_2, |py, m| {
    m.add(py, "__doc__", "This module is implemented in Rust.")?;
    m.add(py, "sum_col", py_fn!(py, sum_col(val: Int64Array)))?;
    Ok(())
});
$ cargo build --release
...
error[E0277]: the trait bound `arrow::array::array::PrimitiveArray<arrow::datatypes::Int64Type>: cpython::FromPyObject<'_>` is not satisfied
  --> src/lib.rs:15:26
   |
15 |     m.add(py, "sum_col", py_fn!(py, sum_col(val: Int64Array)))?;
   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `cpython::FromPyObject<'_>` is not implemented for `arrow::array::array::PrimitiveArray<arrow::datatypes::Int64Type>`
   |
   = note: required by `cpython::FromPyObject::extract`
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

person kemri    schedule 17.09.2019    source источник
comment
отправил электронное письмо по адресу [email protected], и Уэс ответил (в двух словах), что этой функции в настоящее время не существует, хотя над ней работают. Вот цепочка адресов электронной почты: lists.apache.org/list.html?user @ arrow.apache.org   -  person kemri    schedule 20.09.2019
comment
Нулевое копирование AFAIR невозможно, потому что разные платформы будут использовать разные способы сохранения пропущенных значений (NA).   -  person jangorecki    schedule 19.11.2020


Ответы (1)


Здесь есть несколько вопросов:

  1. Как Spark обменивается данными с Python?

    Это выполняется через сокет с использованием формата Arrow IPC, поэтому это не совсем нулевая копия, но все же намного быстрее, чем альтернативы

  2. Как вообще достигается нулевое копирование?

    Известные мне подходы заключаются в передаче адресов указателей между реализациями. Например, модуль Gandiva в Arrow делает это через [JNI] (https://github.com/apache/arrow/blob/master/java/gandiva/src/main/java/org/apache/arrow/gandiva/evalator/JniWrapper.java#L65) путем передачи адресов буфера данных и повторной сборки их в RowBatch.

    Второй подход специально для взаимодействия Python / Java - Jpype хотя реализация не завершена на 100%.

    Вы потенциально можете сделать что-то подобное в pyarrow, создав буферы из указатели и объединение их в массивы

  3. Как это можно сделать в Rust?

    У меня нет опыта в Rust, но вы можете отправить по электронной почте список рассылки Arrow users @ или dev @, чтобы узнать, что сделали другие, или есть возможность внести свой вклад для стандартизации.

person Micah Kornfield    schedule 17.09.2019
comment
очень полезная информация и ссылки, особенно по компоненту IPC. Мне нужно будет поиграть с тем, как это на самом деле работает при преодолении языковых барьеров, но для меня это определенно шаг в правильном направлении - спасибо! - person kemri; 18.09.2019