我正在编写一个来自传感器的流数据应用程序,然后以各种方式处理数据。这些处理组件包括可视化数据,一些数字运算(线性代数),以及以HDF5格式将数据写入磁盘。理想情况下,这些组件中的每一个都是它自己的模块,所有模块都在同一个Python进程中运行,因此IPC不是问题。这引出了如何有效存储流数据的问题。
数据集非常大(~5Gb),因此我希望通过在需要访问的组件之间共享数据来最小化内存中数据的副本数量。如果所有组件都直接ndarray
使用,那么这应该是直截了当的:给其中一个进程提供数据,然后使用ndarray.view()
给其他人一个副本。
但是,将数据写入磁盘的组件将数据存储在HDF5 Dataset
中。它们可以通过多种方式与ndarray
互操作,但似乎创建view()
的工作方式与ndarrary
不同。
观察ndarray
s:
>>> source = np.zeros((10,))
>>> view = source.view()
>>> source[0] = 1
>>> view[0] == 1
True
>>> view.base is source
True
但是,这不适用于HDF5 Dataset
s:
>>> import h5py
>>> file = h5py.File('source.h5', 'a')
>>> source_dset = file.create_dataset('source', (10,), dtype=np.float64)
>>> view_dset = source_dset.value.view()
>>> source_dset[0] = 1
>>> view_dset[0] == 1
False
>>> view_dset.base is source_dset.value
False
仅仅分配Dataset.value
本身,而不是view
也不起作用。
>>> view_dset = source_dset.value
>>> source_dset[0] = 2
>>> view_dset[0] == 2
False
>>> view_dset.base is source_dset.value
False
所以我的问题是:有没有办法让ndarray
共享内存与HDF5 Dataset
,就像两个ndarray
可以共享内存一样?
我的猜测是,这不太可行,可能是因为HDF5如何将数组存储在内存中。但这对我来说有点混乱,特别是type(source_dset.value) == numpy.ndarray
和OWNDATA
的{{1}}标志实际上是Dataset.value.view()
。谁拥有False
正在解释的记忆?
版本细节:Python 3,NumPy版本1.9.1,h5py版本2.3.1,HDF5版本1.8.13,Linux。
其他细节:HDF5文件已分块。
修改:
在更多地讨论之后,似乎一种可能的解决方案是给其他组件提供对HDF5 view
本身的引用。这似乎不会复制任何内存(至少不符合Dataset
),并且源top
中的更改会反映在视图中。
Dataset
我对此解决方案感到相当满意(只要节省内存),但我仍然很好奇为什么上面的>>> import h5py
>>> file = h5py.File('source.h5', 'a')
>>> source = file.create_dataset('source', (10,), dtype=np.float64)
>>> class Container():
... def __init__(self, source_dset):
... self.dset = source_dset
...
>>> container = Containter(source)
>>> source[0] = 1
>>> container.dset[0] == 1
True
方法不起作用。
答案 0 :(得分:0)
简短的回答是,您无法在numpy
数组和h5py
数据集之间共享内存。虽然他们有类似的API(至少在索引时),但他们没有兼容的内存布局。实际上,除了缓存之外,数据集甚至不在内存中 - 它在文件上。
首先,我不明白为什么需要将source.view()
与numpy
数组一起使用。是的,从数组中选择或重塑数组时,numpy
会尝试返回view
而不是副本。但.view
的大多数(所有?)示例都涉及某种转换,例如使用dtype
。你能指出只有.view()
的代码或文档示例吗?
我对h5py
没有太多经验,但是它的文档谈到它提供了一个类似于h5
文件对象的类似ndarray的包装器。您的DataSet
不是ndarray
。例如,它缺少许多ndarray
方法,包括view
。
但索引DataSet
会返回ndarray
,例如view_dset[:]
。 .value
也是如此。其文档的第一部分(通过view_dset.value??
中的IPython
):
Type: property
String form: <property object at 0xb4ee37d4>
Docstring: Alias for dataset[()]
...
请注意,在为DataSet分配新值时,必须直接索引source_dset
。索引值不起作用 - 除了修改数组。它不会更改文件对象。
从数组创建数据集不会将它们更紧密地链接起来:
x = np.arange(10)
xdset = file.create_dataset('x', data=x)
x1 = xdset[:]
x
,xdset
和x1
都是独立的 - 改变一个不会改变其他人。
关于时间,比较
timeit np.sum(x) # 11.7 µs
timeit np.sum(xdset) # 203 µs
timeit xdset.value # 173 µs
timeit np.sum(x1) # same as for x
数组的sum
比数据集快得多。大部分额外时间都涉及从数据集创建数组。