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
当 MemoryView 暴露嵌套数组时,包含每个维度偏移量的
ndim
大小数组。当 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
的成员填充为一维字节数组。
-
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
。