我想在数据处理管道中减少内存复制步骤。
我想做以下事情:从自定义C库生成一些数据将生成的数据输入到运行的MXNet模型中……
我想出了一个实现这个目标的hacky方法。这是一个小例子。
from ctypes import * import numpy as np import mxnet as mx m = mx.ndarray.zeros((4,4)) m.wait_to_read() # make sure the data is allocated c_uint64_p = POINTER(c_uint64) handle= cast(m.handle, c_uint64_p) # NDArray* ptr_ = cast(handle[0], c_uint64_p) # shared_ptr<Chunk> dptr = cast(ptr_[0], POINTER(c_float)) # shandle.dptr n = np.ctypeslib.as_array(dptr, shape=(4,4)) # m and n will share buffer
我通过查看MxNet C ++源代码得出了上面的代码。一些解释:
首先,请注意 NDArray.handle 属性。它是 c_void_p 。阅读python源代码,你就会知道它 NDArrayHandle 。现在深入了解 src/c_api/c_api_ndarray.cc 代码,它被重新解释为 NDArray* 。
NDArray.handle
c_void_p
NDArrayHandle
src/c_api/c_api_ndarray.cc
NDArray*
在源代码树中,转到 include/mxnet/ndarray.h 并找到 NDArray 类。第一个字段是:
include/mxnet/ndarray.h
NDArray
/*! \brief internal data of NDArray */ std::shared_ptr<Chunk> ptr_{nullptr};
检查 Chunk ,这是一个在里面定义的结构 NDArray , 我们看:
Chunk
/*! \brief the real data chunk that backs NDArray */ // shandle is used to store the actual values in the NDArray // aux_handles store the aux data(such as indices) if it's needed by non-default storage. struct Chunk { /*! \brief storage handle from storage engine. for non-default storage, shandle stores the data(value) array. */ Storage::Handle shandle;
最后, shandle 定义于 include/mxnet/storage.h :
shandle
include/mxnet/storage.h
struct Handle { /*! * \brief Pointer to the data. */ void* dptr{nullptr};
写一个小程序显示 sizeof(shared_ptr<some_type>) 是16.基于 这个 问题,我们可以猜到 shared_ptr 由两个指针组成。找出第一个指针是指向数据的指针并不难。把所有东西放在一起,所需要的只是两个指针去参考。
sizeof(shared_ptr<some_type>)
shared_ptr
在下层站点,此方法不能在生产环境或大型项目中使用。它可能会在未来发布时破坏,或者引入棘手的漏洞和安全漏洞。