import h5py
import numpy as np
一、数据和元数据的组织:
In [12]: temperature=np.random.random(1024)
In [13]: temperature
Out[13]:
array([ 0.91976222, 0.07664957, 0.28241276, ..., 0.93644539,
0.89382664, 0.37702447])
假设这些数据来自某个气象站十秒一次的温度采样。为了让这些数据有意义,我们还需要记录采样的时间间隔“delta-T”。以及记录第一个数据获取的时间起点,以及这些数据来自8号气象站:
dt = 10.0
start_time = 1533971134
station = 8
我们可以用一个简单的Numpy内建函数np.savez来将这些数据存入磁盘:
np.savez("weather.npz",data=temperature,start_time=start_time,station=station)
我们可以用 np.load 从文件中获取这些数据:
In [18]: out = np.load("weather.npz")
In [19]: out['data']
Out[19]:
array([ 0.91976222, 0.07664957, 0.28241276, ..., 0.93644539,
0.89382664, 0.37702447])
In [20]: out['start_time']
Out[20]: array(1533971134)
In [21]: out['station']
Out[21]: array(8)
如果我们的气象站数据不止一组怎么办,比如还要一组风速数据:
In [23]: wind = np.random.random(2048)
In [24]: dt_wind = 5.0
在假设我们不止一个气象站。也许我们可以引入某种命名规范,比如“wind_8”作为8号气象站的风速数据,“dt_wind_8”作为采样时间间隔。那么或许我们需要使用多个文件去完成。
现在我们使用 HDF5 来存储试试:
In [25]: f = h5py.File('weather.hdf5')
In [26]: f['/8/temperature'] = temperature
In [27]: f['/8/temperature'].attrs['dt'] = 10.0
In [28]: f['/8/temperature'].attrs['start_time'] = 1533971134
In [29]: f['/8/wind'] = wind
In [30]: f['/8/wind'].attrs['dt'] = 5.0
......
In [31]: f['/9/temperature'] = temperature_9
取出:
In [40]: dataset = f['/8/temperature']
In [41]: dataset[:10]
Out[41]:
array([ 0.91976222, 0.07664957, 0.28241276, 0.68921452, 0.59650297,
0.50639705, 0.87994178, 0.07439151, 0.40971268, 0.81227045])
In [42]: dataset.value
Out[42]:
array([ 0.91976222, 0.07664957, 0.28241276, ..., 0.93644539,
0.89382664, 0.37702447])
In [43]: for key,value in dataset.attrs.items():
...: print(f'{key}:{value}')
...:
dt:10.0
start_time:1533971134
HDF5数据模型的三大要素:
数据集:一种数组型对象,在磁盘上保存数值类型的数据;
组:层次性容器,可以包含数据集和子组;
特征:自定义元数据信息,可被附加在数据集以及组上。
查看 key:
In [49]: list(f.keys())
Out[49]: ['8']
In [50]: list(f['/8'].keys())
Out[50]: ['temperature', 'wind']
二、开始使用 HDF5
f = h5py.File('name.hdf5', 'w') # 写
f = h5py.File('name.hdf5', 'r') # 读
f = h5py.File('name.hdf5', 'r+') # 读写
f = h5py.File('name.hdf5', 'a') # 追加
f = h5py.File('name.hdf5', 'w-') # 写,如果存在此文件,则会报错,避免了覆盖原文件
f.close() # 别忘了保存后关闭文件
__文件驱动
文件驱动处于文件系统和 HDF5 高级抽象(组、数据集和特征)之间。一般情况下是无需设置的,因为默认的驱动适用于大部分应用程序。
1、core 驱动:
core 驱动会将你的文件保存在内存中,它对于能够存储的数据量显然是有限的,但是优点是超快速读写。
f = h5py.File('name.hdf5',driver='core')
# 还可以在要求 HDF5 在磁盘上创建一个 “备份存储” 文件,
# 当内容中的文件映象被关闭时,其内容会被保存到磁盘上。
f = h5py.File('name.hdf5',driver='core',backing_store=True)
2、mpio 驱动:
并发 HDF5 的核心,它允许多个同时运行的进程访问同一个文件。你可以同时有成百上千个并发计算的进程,他们在共享访问磁盘上同一个文件时能保证数据的一致性。将在以后会介绍到。
——用户块:
f = h5py.File('name.hdf5','w',userblock_size=512)
f.close()
with open('name.hdf5', 'r+') as f:
f.write('a'*512)
三、使用数据集:
创建空数据集:
In [93]: dset = f.create_dataset('test1',(10,10))
In [94]: dset
Out[94]:
In [95]: dset = f.create_dataset('test2',(10,10),dtype=np.complex64)
In [96]: dset
Out[96]:
四、HDF5 并发:多线程:
由于 GIL,一个基于线程的python程序只能一次使用一个处理器的时间。所以在HDF5上使用多线程,在效率上并没有多大提升
import threading
import time
import random
import numpy as np
import h5py
class ComputeThread(threading.Thread):
def __init__(self,axis):
self.axis = axis
threading.Thread.__init__(self)
def run(self):
for idx in range(1024):
random_number = random.random()*0.01
time.sleep(random_number)
with lock:
dset[self.axis,idx] = random_number
if __name__ == '__main__':
f = h5py.File('thread.hdf5','w')
dset = f.create_dataset('data',(2,1024),dtype='f')
lock = threading.RLock()
thread1 = ComputeThread(0)
thread2 = ComputeThread(1)
thread1.start()
thread2.start()