我正在编写一个应用程序,用于从传感器流式传输数据,然后以各种方式处理数据。这些处理组件包括可视化数据、一些数字处理(线性代数),以及以HDF5格式将数据写入磁盘。理想情况下,这些组件中的每一个都是自己的模块,都在同一个Python进程中运行,这样IPC就不成问题了。这就引出了如何有效地存储流数据的问题。
这些数据集相当大(~5Gb),因此我希望通过在需要访问的组件之间共享数据来最小化内存中数据的副本数量。如果所有组件都直接使用ndarrays,那么这应该很简单:给其中一个进程提供数据,然后使用ndarray.view()给其他每个进程一个副本。
但是,将数据写入磁盘的组件将数据存储在HDF5Dataset中。它们在很多方面都可以与ndarrays互操作,但是创建view()并不像与ndarrarys一样工作。
ndarrays观察:

>>> source = np.zeros((10,))
>>> view = source.view()
>>> source[0] = 1
>>> view[0] == 1
True
>>> view.base is source
True

但是,这不适用于HDF5Datasets:
>>> 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与一个HDF5Dataset共享内存,就像两个ndarray可以共享内存一样?
我的猜测是,这不太可能奏效,可能是因为HDF5在内存中存储数组的方式有些微妙。但我有点困惑,尤其是type(source_dset.value) == numpy.ndarrayOWNDATADataset.value.view()标志实际上是False。谁拥有view正在解释的记忆?
版本详细信息:Python 3,NumPy Version 1.9.1,h5py Version 2.3.1,HDF5 version1.8.13,Linux。
其他详细信息:HDF5文件被分块。
编辑:
在对此进行了更多的讨论之后,似乎有一种可能的解决方案是给其他组件一个HDF5Dataset本身的引用。这似乎不会复制任何内存(至少不符合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

我对这个解决方案相当满意(只要能节省内存),但我仍然好奇为什么上面的view方法不起作用。

最佳答案

简而言之,您不能在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[()]
...

注意,当为数据集分配新值时,必须直接索引source_dset。除了修改数组外,索引值不起作用。它不会更改文件对象。
从数组创建数据集不会将它们更紧密地链接起来:
x = np.arange(10)
xdset = file.create_dataset('x', data=x)
x1 = xdset[:]

xxdsetx1都是独立的-改变一个不会改变另一个。
关于时代,比较一下
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比数据集快得多。大多数额外的时间都用于从数据集创建数组。

关于python - 如何使用NumPy ndarray共享HDF5数据集中的内存,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27409512/

10-12 21:02
查看更多