基于 Apache Arrow 的 MATLAB 接口设计指南:从 arrow.* 包到跨语言零拷贝内存共享
2026/9/23 20:07:42 网站建设 项目流程

基于 Apache Arrow 的 MATLAB 接口设计指南:从 arrow.* 包到跨语言零拷贝内存共享

【免费下载链接】arrowApache Arrow is a multi-language toolbox for accelerated data interchange and in-memory processing项目地址: https://gitcode.com/gh_mirrors/arrow13/arrow

Apache Arrow 是一个面向加速数据交换与内存分析的跨语言工具箱,其 MATLAB 接口(MATLAB Interface for Apache Arrow)旨在让 MATLAB 用户直接创建、访问与释放 Arrow 内存,并通过 Arrow 生态的列式内存格式与文件格式(Feather、Parquet、IPC)同 Python、R、Rust 等语言高效互通。本文以仓库中的设计文档 matlab/doc/matlab_interface_for_apache_arrow_design.md 为主线,结合matlab/目录下的真实源码,完整讲解其设计动机、API 骨架、三大核心用例(UC1/UC2/UC3)的落地路径,以及测试、文档与安装规划,帮助读者掌握该接口的设计全貌与工程实现细节。

设计背景与目标

设计文档将 Apache Arrow 的列式分析能力定位为构建 MATLAB 接口的出发点,并明确聚焦三个为未来更高级用例奠基的核心场景:

  1. UC1:使用 MATLAB 代码创建、访问和删除 Arrow 内存。
  2. UC2:使用 MATLAB 代码将 Arrow 内存序列化/反序列化到 Parquet、Feather、JSON、CSV 等文件格式。
  3. UC3:将以 MATLABtable表示的内存表格数据以最小开销(理想情况下为零拷贝)迁移到 Python、R、Rust 等其他语言。

这三个用例共同决定了接口的形态:既要有面向普通用户的数组与表格对象模型,也要有面向文件读写的 IO 能力,还要有面向跨语言内存共享的 C 级互操作层。

总体设计:arrow.*包与 C++ 包装层

设计文档设想了一套以arrow.*命名的包化类与函数,使用户能够通过 MATLAB 代码与 Arrow C++ 库的核心功能交互。这一设计在当前仓库中已经落地为matlab/src/matlab/+arrow/目录下的真实实现(MATLAB 中+前缀目录即对应包命名空间)。

MATLAB API 骨架

文档列出的 MATLAB API 与仓库实际实现的对应关系如下:

设计文档中的 API仓库中的实际路径
arrow.Buffermatlab/src/matlab/+arrow/+buffer/Buffer.m
arrow.Arraymatlab/src/matlab/+arrow/+array/Array.m
arrow.RecordBatchmatlab/src/matlab/+arrow/+tabular/RecordBatch.m
arrow.Tablematlab/src/matlab/+arrow/+tabular/Table.m
arrow.Field/arrow.Schemamatlab/src/matlab/+arrow/+type/Field.m、matlab/src/matlab/+arrow/+tabular/Schema.m
arrow.type.DataType及子类matlab/src/matlab/+arrow/+type/Type.m 及其下Float64Type.mStringType.mDate32Type.mTime32Type.mTimestampType.m
arrow.memory.*对应 C++ 侧内存分配,MATLAB 侧以arrow.buffer.BufferfromMATLAB静态工厂等方式呈现

从实现看,arrow.type包下提供了完整的数据类型体系,包括BooleanTypeNumericTypeFloat32/64Int8/16/32/64UInt8/16/32/64)、StringTypeListTypeStructTypeTemporalTypeDate32/64Time32/64Timestamp),以及配套的traits目录,用于把类型 ID 映射到对应的数组代理类与构造器——这正对应文档中"返回类型特定的、arrow.Array抽象类的具体子类"的描述。

C++ API 设计

为了让 MATLAB 与 Arrow C++ 库交互,设计文档提出需要一组用于在 MATLABmxArray与 Arrow C++ 类型之间"包装/解包"(wrap/unwrap)的 C++ API,例如:

  • arrow::matlab::is_array/is_record_batch/is_table
  • arrow::matlab::unwrap_array/wrap_array
  • arrow::matlab::unwrap_record_batch/wrap_record_batch
  • arrow::matlab::unwrap_table/wrap_table

需要说明的是,从当前仓库的 C++ 源码结构看(matlab/src/cpp/arrow/matlab/),最终落地时采用了一种代理(proxy)模式而非文档示例中的unwrap/wrap命名:C++ 侧按功能域组织为array/proxy/tabular/proxy/(含table.ccrecord_batch.ccschema.cc)、buffer/proxy/type/proxy/io/feather/proxy/io/ipc/proxy/io/csv/proxy/c/proxy/等模块,并通过mex/gateway.ccproxy/factory.cc统一注册;MATLAB 侧则通过libmexclass.proxy.Proxy持有对应 C++ 代理的 ID 来调用底层能力。文档中的unwrap/wrap是设计阶段的功能示意,其"把 MATLAB 对象解析为 Arrow C++ 对象"的语义在 proxy 实现中得到等价承接。

用例详解一(UC1):用 MATLAB 代码创建与操作 Arrow 内存

文档描述了 UC1 的核心场景:MATLAB 开发者可以用"普通"的 MATLAB 数组(例如double类型的数值行向量)创建arrow.Array,然后对其进行索引/切片、获取类型、从工作区清除等操作。arrow.array工厂函数会根据输入数组的 MATLAB 类型,返回arrow.Array抽象类的类型特定具体子类。

arrow.array工厂函数的分发逻辑

仓库中的 matlab/src/matlab/+arrow/array.m 完整实现了这一分发机制:

  • logicalarrow.array.BooleanArray
  • uint8/16/32/64→ 对应的UInt*Array
  • int8/16/32/64→ 对应的Int*Array
  • singleFloat32ArraydoubleFloat64Array
  • string(以及cellstr,通过convertCellstrToString支持)→StringArray
  • datetimeTimestampArraydurationTime64Array
  • tableStructArraycellListArray
  • 其他类型抛出arrow:array:UnsupportedMATLABType错误

例如,向arrow.array传入double数组会得到arrow.Float64Array,与文档示例一致。

missing 值自动转为 Arrow NULL

文档特别指出:MATLAB 的missing值(如NaNNaT<undefined>)在构造arrow.Array子类实例时会自动转换为 Arrow 的NULL值。这一点在源码中也有迹可循:matlab/src/matlab/+arrow/+array/Array.m 暴露了Valid(有效性位图)依赖属性,并通过NumElementsValid统计NumNulls用于显示头信息;底层代理(C++ 侧array/proxy/)负责把 MATLAB 的缺失值编码进 Arrow 的有效性位图中。

文档示例的完整运行

设计文档给出了一个可复现的 MATLAB 会话示例:

>> A = randi(100, 1, 5) A = 82 91 13 92 64 >> class(A) ans = 'double' >> A(4) = NaN; % Set the fourth element to NaN. >> AA = arrow.array(A); % Create an arrow.Array from A. >> class(AA) ans = 'arrow.Float64Array' >> AA(3:5) % Extract elements at indices 3 to 5 from AA. ans = 13 <NULL> 64 >> clear AA; % Clear AA from workspace and release Arrow C++ memory.

索引AA(3:5)得到13 <NULL> 64,其中索引 4 处正是NaN被转换为 ArrowNULL后的显示结果。clear AA会释放底层 C++ 代理,从而回收 Arrow C++ 内存。从源码看,Array.m中的NumElementsValidType三个依赖属性为这类操作提供了基础元数据,toString/displayScalarObject实现了带<NULL>标记的展示逻辑。

用例详解二(UC2):MATLAB 数据与 Feather 等文件格式的序列化

UC2 的目标是让 MATLAB 数据能够通过 Arrow 内存序列化到磁盘文件(如 Feather、Parquet),并能读回。设计文档给出了从 MATLABtable到 Feather 文件的完整开发流程。

方式一:用arrow.Array组合成arrow.Table

开发者可以先为每个表变量构造arrow.Array,再组合成arrow.Table

>> Var1 = arrow.array(["foo"; "bar"; "baz"]); >> Var2 = arrow.array([today; today + 1; today + 2]); >> Var3 = arrow.array([10; 20; 30]); >> AT = arrow.Table(Var1, Var2, Var3);

方式二:直接从 MATLABtable转换

文档设想了arrow.matlab2arrow这样的转换函数;从当前仓库实现看,这一职责由 matlab/src/matlab/+arrow/table.m 承担——它接收一个 MATLABtable(通过istable校验),调用arrow.tabular.internal.decompose将各列拆解为arrow.Array,收集列名后创建arrow.tabular.Table代理:

>> Weight = [10; 24; 10; 12; 18]; >> Radius = [80; 135; 65; 70; 150]; >> Density = [10.2; 20.5; 11.2; 13.7; 17.8]; >> T = table(Weight, Radius, Density); % Create a MATLAB table >> AT = arrow.table(T); % Create an arrow.Table

反向转换则由 matlab/src/matlab/+arrow/+tabular/Table.m 的table()/toMATLAB()方法完成:它逐列取出ChunkedArray并调用toMATLAB,再用makeValidVariableNamesmakeValidDimensionNames生成合法的 MATLAB 变量名与维度名后组装回 MATLABtable

写入与读取 Feather 文件

文档示例中通过arrow.FeatherTableWriter写入、通过arrow.FeatherTableReader读取:

>> featherTableWriter = arrow.FeatherTableWriter(); >> featherTableWriter.write(AT, "data.feather");
>> featherTableReader = arrow.FeatherTableReader("data.feather"); >> AT = featherTableReader.read();

在当前仓库中,Feather 读写的底层实现位于 C++ 侧 matlab/src/cpp/arrow/matlab/io/feather/proxy/writer.cc 与reader.cc(基于 Arrow C++ 的arrow::ipc::feather能力),MATLAB 侧则由 matlab/src/matlab/+arrow/+internal/+io/+feather/Writer.m 等内部类封装;同时在包根目录提供了面向普通用户的顶层函数 matlab/src/matlab/featherwrite.m 与 matlab/src/matlab/featherread.m,这正是下文"高级工作流"中设想的featherwrite高层接口。

高级用户工作流:编写 MEX 函数扩展写入能力

文档指出,要新增"写入 Feather 文件"这类能力,高级 MATLAB 用户需要:

  1. 编写一个可被 MATLAB 直接调用的MEX 函数(例如featherwriteMEX);
  2. 在 MEX 函数内部使用arrow::matlab::unwrap_table把 MATLAB 侧的arrow.Table转换为 C++ 侧的arrow::Table
  3. 将 C++arrow::Table交给 Arrow C++ 库的写入 API(如arrow::ipc::feather::WriteTable)完成落盘。

读取方向(arrow.FeatherTableReader)遵循相同思路。这与仓库中 C++ 侧按"proxy + 面向 MEX 的 gateway"组织的方式一致:mex/gateway.cc是 MEX 入口的枢纽,各功能域的 proxy 类持有真实的 Arrow C++ 对象,MATLAB 调用经libmexclass代理转发到这些 proxy 方法。

赋能高层工作流

设计文档的核心思想是分层:面向高级用户的构建块 APIarrow.*类与 C++ API)+面向日常用户的薄封装(如featherwrite)。文档用一张"代码流图"(Code flow diagram)总结了高级用户需要创作的各个部分——从arrow.Table解包、MEX 函数、调用 Arrow C++ 写入 API,再到暴露给普通 MATLAB 用户的高层函数。当前仓库 matlab/src/matlab/featherwrite.m 与featherread.m的存在即是该"高层工作流"设计的直接产物;测试方面,matlab/test/tfeather.m 以及matlab/test/arrow下的用例对读写往返(roundtrip)进行了验证。

用例详解三(UC3):进程内与进程外的内存共享

Arrow 支持多种本地内存共享方式,文档将其划分为两大类:

  1. 进程内内存共享(In-Process Memory Sharing)
  2. 进程外内存共享(Out-of-Process Memory Sharing)

进程内共享:借助 Arrow C Data Interface 与 PyArrow 零拷贝互通

MATLAB 支持在 MATLAB 进程内运行 Python 代码,因此 MATLAB 与 Python 共享同一虚拟地址空间,理论上可以在两者之间高效共享 Arrow 内存。Arrow 为此定义了C Data Interface——一套轻量级的 C API,用于在同一地址空间内的多种语言之间共享 Arrow 数据与元数据。

其核心是两个 C 风格结构体:

  • ArrowArray:表示 Arrow 数据(内容遵循 Arrow Columnar Format);
  • ArrowSchema:表示相关的元数据(类型、字段等)。

MATLAB → PyArrow 方向:调用arrow.ArrayexportToCDataInterface方法,把数组导出为 C Data Interface 格式,得到两个结构体的内存地址;这些地址可以直接传给 Python(不复制底层数据),再通过pyarrow.Array._import_from_c构造pyarrow.Array

% Create a MATLAB arrow.Array. >> AA = arrow.array([1, 2, 3, 4, 5]); % Export the MATLAB arrow.Array to the C Data Interface format, returning the % memory addresses of the required ArrowArray and ArrowSchema C-style structs. >> [arrayMemoryAddress, schemaMemoryAddress] = AA.exportToCDataInterface(); % Import the memory addresses of the C Data Interface format structs to create a pyarrow.Array. >> PA = py.pyarrow.Array._import_from_c(arrayMemoryAddress, schemaMemoryAddress);

PyArrow → MATLAB 方向:先用pyarrow.Array._export_to_c导出,再把地址交给arrow.Array.importFromCDataInterface静态方法零拷贝构造 MATLABarrow.Array

% Make a pyarrow.Array. >> PA = py.pyarrow.array([1, 2, 3, 4, 5]); % Create ArrowArray and ArrowSchema C-style structs adhering to the Arrow C Data Interface format. >> array = py.pyarrow.cffi.ffi.new("struct ArrowArray*") >> arrayMemoryAddress = py.int(py.pyarrow.cffi.ffi.cast("uintptr_t", array)); >> schema = py.pyarrow.cffi.ffi.new("struct ArrowSchema*") >> schemaMemoryAddress = py.int(py.pyarrow.cffi.ffi.cast("uintptr_t", schema)); % Export the pyarrow.Array to the C Data Interface format, populating the required ArrowArray and ArrowShema structs. >> PA.export_to_c(arrayMemoryAddress, schemaMemoryAddress) % Import the C Data Interface structs to create a MATLAB arrow.Array. >> AA = arrow.Array.importFromCDataInterface(arrayMemoryAddress, schemaMemoryAddress);

(第二个示例改编自 PyArrow 的test_cffi.py测试用例。)

在仓库源码中,这一互操作能力有完整的实现支撑:MATLAB 侧 matlab/src/matlab/+arrow/+c/Array.m 是 C Data Interface 中ArrowArray结构体指针的包装(提供Address属性),arrow.c.Schema对应ArrowSchema;Array.m 的export(obj, cArrowArrayAddress, cArrowSchemaAddress)方法把地址传给代理执行导出,而静态方法import(Array.m)借助arrow.c.internal.ArrayImporter完成导入;C++ 侧 matlab/src/cpp/arrow/matlab/c/proxy/array.cc、array_importer.ccschema.cc则直接操作ArrowArray/ArrowSchema结构体并接入 Arrow C++ 的 C Data Interface 支持。

进程外共享:内存映射 IPC 文件

对于多进程"数据处理流水线"中的大表,文档推荐将arrow.Table序列化为Arrow IPC File Format,再由独立进程中的 PyArrow 对文件做内存映射(memory-mapped)零拷贝读取。由于 IPC File Format 与内存中的 Arrow 格式是磁盘上 1:1 的映射,内存映射读取无需自定义反序列化/转换即可构造pyarrow.Table,性能极高。

% Create a MATLAB arrow.Table. >> Var1 = arrow.array(["foo", "bar", "baz"]); >> Var2 = arrow.array([today, today + 1, today + 2]); >> Var3 = arrow.array([10, 20, 30]); >> AT = arrow.Table(Var1, Var2, Var3); % Write the MATLAB arrow.Table to the Arrow IPC File Format on disk. >> arrow.ipcwrite(AT, "data.arrow"); % Run Python in a separate process. >> pyenv("ExecutionMode", "OutOfProcess"); % Memory map the Arrow IPC File. >> memoryMappedFile = py.pyarrow.memory_map("data.arrow"); % Construct pyarrow.ipc.RecordBatchFileReader to read the Arrow IPC File. >> recordBatchFileReader = py.pyarrow.ipc.open_file(memoryMappedFile); % Read all record batches from the Arrow IPC File in one-shot and return a pyarrow.Table. >> PAT = recordBatchFileReader.read_all()

文档设想的arrow.ipcwrite在仓库中的对应实现是 matlab/src/matlab/+arrow/+io/+ipc/RecordBatchFileWriter.m:它接受文件名与arrow.tabular.Schema构造,提供writeRecordBatchwriteTable以及按输入类型自动分发的write方法,并在close时关闭底层文件;读取方向对应 RecordBatchFileReader.m。C++ 侧 matlab/src/cpp/arrow/matlab/io/ipc/proxy/record_batch_file_writer.cc 与record_batch_file_reader.cc封装了 Arrow C++ 的 IPC 读写能力,实现writeTable时会把 MATLAB 的arrow.Table代理转换为 C++arrow::Table后再写入——与 UC2 中"unwrap 后调用 C++ API"的思想一脉相承。

测试、文档与安装策略

测试基础设施

设计文档要求至少包含三类测试基础设施:

  1. MATLAB 类化单元测试(Class-Based Unit Tests)matlab/test/目录即为此服务,其中tfeather.m等测试文件覆盖 Feather 读写等核心功能;
  2. MATLAB CI 工作流:仓库ci/docker/ci/scripts/中与 MATLAB 相关的构建/测试脚本(如c_glib_test.sh等)配套完成持续集成;
  3. 集成测试(Integration Testing):文档建议参考 Apache Arrow 官方的集成测试格式,验证跨语言的一致性。

实现要点:为了测试内部 C++ 代码,可以用 MEX 函数从 MATLAB 类化单元测试中调用 C++ 代码——这与 UC2 中"MEX 函数作为 MATLAB 与 C++ 桥梁"的设计完全一致。

文档规划

为保证可用性、可发现性与可访问性,设计文档规划了以下文档工作:

  1. MATLAB API 的Help Text
  2. MATLAB API 参考手册;
  3. MATLAB 与 C++ API 的使用示例;
  4. 面向构建与安装的 README;
  5. 构建系统文档;
  6. CI 集成文档。

安装方式

文档的长期目标是让 MATLAB 用户无需编译 MEX 函数或进行任何手动配置即可安装,其机制与 JavaScript 用户通过npm安装apache-arrow、Rust 用户通过cargo安装arrowcrate 类似——即通过 MATLAB 的Add-On Explorer安装可选软件包。

在尚无可直接安装的 MATLAB Add-On 的短期阶段,规划包括:

  • 在仓库中维护最新、清晰、面向近期 MATLAB 版本的构建与安装说明(即 matlab/README.md 与 matlab/CMakeLists.txt 所承载的内容);
  • 通过 CI 工作流为 Windows、Mac、Linux 定期构建预编译的 MEX 函数,让用户无需手动从头构建 MEX 接口即可体验最新功能。

路线图

设计文档以一张路线图表总结各能力的开发计划:

CapabilityUse CaseTimeframe
Arrow Memory InteractionUC1Near Term
File Reading/WritingUC2Near Term
In/Out-of-Process Memory SharingUC3Mid Term

对照当前仓库的代码成熟度,可以推断:UC1 与 UC2 所依赖的数组体系、arrow.table/Table、Feather 读写(featherwrite/featherread)与 IPC 读写(arrow.io.ipc.*)已经具备完整实现;UC3 所依赖的 C Data Interface 导入/导出(arrow.c.ArrayArray.exportArray.import)也已在 C++ 与 MATLAB 双层落地。整体上,设计文档描绘的"包化 API + proxy 式 C++ 桥接 + 高层薄封装"的三层架构,在仓库中均有对应的工程实体可供读者进一步深入研读。

【免费下载链接】arrowApache Arrow is a multi-language toolbox for accelerated data interchange and in-memory processing项目地址: https://gitcode.com/gh_mirrors/arrow13/arrow

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询