MemoryView¶ ↑
MemoryView 提供了在扩展库之间共享内存中固定大小元素的同构多维数组的功能。
免责声明¶ ↑
-
此功能仍处于实验阶段。此处描述的规范将来可能会更改。
-
本文档正在建设中。请参考 ruby 的 master 分支以获取此文档的最新版本。
概述¶ ↑
我们有时会处理某些类型的对象,这些对象在连续的内存区域上具有相同类型固定大小元素的数组作为其内部表示。numo-narray 中的 Numo::NArray 和 rmagick 中的 Magick::Image 就是此类对象的典型示例。MemoryView 充当中心,在这些库之间共享此类对象的内部数据,无需复制。
在某些领域(如数据分析、机器学习和图像处理)中,无复制的数据共享非常重要。在这些领域,人们需要使用多个库处理大量的内存数据。如果我们被迫复制来在库之间交换大量数据,那么大量的数据处理时间必须被复制数据所占用。通过使用 MemoryView,您可以避免这种时间浪费。
MemoryView 有两个类别的 API
-
生产者 API
类可以注册自己的 MemoryView 条目,这允许该类的对象公开其 MemoryView
-
消费者 API
消费者 API 允许我们获取和管理对象的 MemoryView
MemoryView 结构¶ ↑
MemoryView 结构 rb_memory_view_t
用于导出对象的 MemoryView。此结构包含对象的引用(即 MemoryView 的所有者)、指向导出内存头部的指针以及描述内存结构的元数据。元数据可以描述带步幅的多维数组。
MemoryView 结构的成员¶ ↑
MemoryView 结构由以下成员组成。
-
VALUE obj
对原始对象的引用,该对象具有通过 MemoryView 导出的内存。
RubyVM
管理 MemoryView 导出对象的引用计数,以保护它们免受垃圾回收。消费者不必费力保护此对象免受GC
的影响。 -
void *data
指向导出内存头部的指针。
-
ssize_t byte_size
data
指向的内存中的字节数。 -
bool readonly
对于只读内存为
true
,对于可写内存为false
。 -
const char *format
用于描述元素格式的字符串,或对于无符号字节为 NULL。
-
ssize_t item_size
每个元素中的字节数。
-
const rb_memory_view_item_component_t *item_desc.components
元素中组件的元数据数组。
-
size_t item_desc.length
item_desc.components
中的项目数。 -
ssize_t ndim
维数。
-
const ssize_t *shape
一个
ndim
大小的数组,指示每个维度中的元素数量。当ndim
为 1 时,这可以是NULL
。 -
const ssize_t *strides
一个
ndim
大小的数组,指示在每个维度中跳到下一个元素要跳过的字节数。当ndim
为 1 时,这可以是NULL
。 -
const ssize_t *sub_offsets
一个
ndim
大小的数组,由当 MemoryView 公开嵌套数组时每个维度中的偏移量组成。当 MemoryView 公开扁平数组时,这可以是NULL
。 -
void *private_data
MemoryView 提供者在内部使用的私有数据。当不需要任何私有数据时,这可以是
NULL
。
MemoryView API¶ ↑
对于使用者¶ ↑
-
bool rb_memory_view_available_p(VALUE obj)
如果
obj
支持导出 MemoryView,则返回true
。否则返回false
。如果此函数返回
true
,则不意味着函数rb_memory_view_get
将会成功。 -
bool rb_memory_view_get(VALUE obj, rb_memory_view_t *view, int flags)
如果给定的
obj
支持导出符合给定flags
的 MemoryView,则此函数会使用 MemoryView 的信息填充view
并返回true
。在这种情况下,obj
的引用计数会增加。如果给定的
obj
和flags
组合无法导出 MemoryView,则此函数返回false
。在这种情况下,不会触及view
的内容。当不再需要 MemoryView 时,必须使用
rb_memory_view_release
释放导出的 MemoryView。 -
bool rb_memory_view_release(rb_memory_view_t *view)
释放给定的 MemoryView
view
并减少view->obj
的引用计数。当不再需要 MemoryView 时,消费者必须调用此函数。如果未能调用此函数,会导致内存泄漏。
-
ssize_t rb_memory_view_item_size_from_format(const char *format, const char **err)
计算元素占用的字节数。
当计算失败时,失败位置的
format
会存储到err
中,并返回-1
。 -
void *rb_memory_view_get_item_pointer(rb_memory_view_t *view, const ssize_t *indices)
计算由给定
indices
指示的项的位置。indices
的长度必须等于view->ndim
。如果需要,此函数会初始化view->item_desc
。 -
VALUE rb_memory_view_get_item(rb_memory_view_t *view, const ssize_t *indices)
返回由给定
indices
指示的项的 Ruby 对象表示形式。indices
的长度必须等于view->ndim
。此函数使用rb_memory_view_get_item_pointer
。 -
rb_memory_view_init_as_byte_array(rb_memory_view_t *view, VALUE obj, void *data, const ssize_t len, const bool readonly)
将 view
的成员填充为 1 维字节数组。
-
void rb_memory_view_fill_contiguous_strides(const ssize_t ndim, const ssize_t item_size, const ssize_t *const shape, const bool row_major_p, ssize_t *const strides)
使用具有给定元素大小的给定形状的连续数组的字节步幅填充 strides
数组。
-
void rb_memory_view_prepare_item_desc(rb_memory_view_t *view)
填充 view
的 item_desc
成员。
-
bool rb_memory_view_is_contiguous(const rb_memory_view_t *view)
如果 MemoryView view
中的数据是行主序或列主序连续的,则返回 true
。
否则返回 false
。
-
bool rb_memory_view_is_row_major_contiguous(const rb_memory_view_t *view)
如果 MemoryView view
中的数据是行主序连续的,则返回 true
。
否则返回 false
。
-
bool rb_memory_view_is_column_major_contiguous(const rb_memory_view_t *view)
如果 MemoryView view
中的数据是列主序连续的,则返回 true
。
否则返回 false
。