Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/359.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何与NumPy ndarray共享HDF5数据集中的内存_Python_Numpy_Hdf5_H5py - Fatal编程技术网

Python 如何与NumPy ndarray共享HDF5数据集中的内存

Python 如何与NumPy ndarray共享HDF5数据集中的内存,python,numpy,hdf5,h5py,Python,Numpy,Hdf5,H5py,我正在编写一个应用程序,用于从传感器传输数据,然后以各种方式处理数据。这些处理组件包括数据可视化、一些数字运算(线性代数),以及以HDF5格式将数据写入磁盘。理想情况下,这些组件中的每一个都是自己的模块,都在同一个Python进程中运行,因此IPC不是问题。这就引出了如何高效地存储流数据的问题 数据集非常大(~5Gb),因此我希望通过在需要访问的组件之间共享数据来最小化内存中的数据副本数量。如果所有组件都直接使用ndarrays,那么这应该很简单:将数据交给其中一个进程,然后使用ndarray.

我正在编写一个应用程序,用于从传感器传输数据,然后以各种方式处理数据。这些处理组件包括数据可视化、一些数字运算(线性代数),以及以HDF5格式将数据写入磁盘。理想情况下,这些组件中的每一个都是自己的模块,都在同一个Python进程中运行,因此IPC不是问题。这就引出了如何高效地存储流数据的问题

数据集非常大(~5Gb),因此我希望通过在需要访问的组件之间共享数据来最小化内存中的数据副本数量。如果所有组件都直接使用
ndarray
s,那么这应该很简单:将数据交给其中一个进程,然后使用
ndarray.view()
给其他每个进程一个副本

但是,将数据写入磁盘的组件将数据存储在HDF5
数据集中。它们可以在许多方面与
ndarray
s互操作,但创建
view()
似乎不像
ndarray
s那样有效

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
仅仅分配
数据集.value本身,而不是它的
视图,也不起作用

>>> 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\u dset.value)==numpy.ndarray
Dataset.value.view()的
OWNDATA
标志实际上是
False
。谁拥有
视图
正在解释的内存

版本详细信息:Python 3、NumPy版本1.9.1、h5py版本2.3.1、HDF5版本1.8.13、Linux

其他详细信息:HDF5文件已分块

编辑

在进一步讨论这个问题之后,一个可能的解决方案似乎是给其他组件一个对HDF5
Dataset
本身的引用。这似乎不会复制任何内存(至少根据
top
),并且源
数据集中的更改会反映在视图中

>>> 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

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

简单的回答是,你不能在
numpy
数组和
h5py
数据集之间共享内存。虽然它们有类似的API(至少在索引方面是如此),但它们没有兼容的内存布局。事实上,除了某种缓存之外,数据集甚至不在内存中——它在文件中


首先,我不明白为什么需要将
source.view()
numpy
数组一起使用。是,当从数组中选择或重塑数组时,
numpy
尝试返回一个
视图,而不是一个副本。但是
.view
的大多数(全部?)示例都涉及某种转换,例如使用
dtype
。您能否仅使用
.view()
指向代码或文档示例

我对
h5py
没有太多经验,但它的文档中提到它在
h5
文件对象周围提供了一个类似于ndarray的薄型包装器。您的
数据集
不是
ndarray
。例如,它缺少许多
ndarray
方法,包括
view

但是索引
数据集
会返回一个
ndarray
,例如
视图\u数据集[:]
.value
也是如此。其文档的第一部分(通过
IPython
中的
view\u dset.value???
):

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

数组的
比数据集快得多。大部分额外的时间都涉及到从数据集创建数组。

请注意,传递数据集对象会对性能造成巨大影响。此外,访问数据集不会一次将其全部加载到内存中,这允许您以最小的内存开销仅提取数据集的一个子集。此外,如果您的数据是分块的,它甚至可能在文件中不是连续的(甚至可能被压缩)。hdf5的主要功能之一是能够任意选择hyberslab,隐藏这些细节是h5py的主要功能之一。@tcaswell澄清数据确实是分块和压缩的,因此在文件中很可能不是连续的。所以我想你是对的,任何给定的块可能存在于内存中,也可能不存在于内存中,因此
ndarray
必须复制数据,而不是引用数据。那它为什么不拥有自己的数据呢?另外,您考虑的性能影响是什么?将
np.sum(data\u set)
np.sum(data\u set[:])
.value
数据集
的一个属性,该数组由一些
getter
函数生成。因此,对
.value
的一次调用可能不会产生与下一次调用相同的对象。预订
h5py
,源代码指示索引操作使用文件中的数据填充新的
ndarray
。我想这样做是为了防止任何抄袭,因为有很多读者,但只有一个作者。但你们的观点被很好地理解了,让NumPy处理查看/复制可能会更好。
x = np.arange(10)
xdset = file.create_dataset('x', data=x)
x1 = xdset[:]
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