Python h5py不符合分块规范?
问题: 我有现有的netCDF4文件(大约5000个)(通常为96x3712x3712形状)数据点(float32)。这些文件的第一个维度是时间(每天1个文件),第二个维度和第三个维度是空间维度。 目前,在第一个维度上制作一个切片(甚至是部分切片)将花费大量时间,原因如下:Python h5py不符合分块规范?,python,h5py,netcdf4,Python,H5py,Netcdf4,问题: 我有现有的netCDF4文件(大约5000个)(通常为96x3712x3712形状)数据点(float32)。这些文件的第一个维度是时间(每天1个文件),第二个维度和第三个维度是空间维度。 目前,在第一个维度上制作一个切片(甚至是部分切片)将花费大量时间,原因如下: netCDF文件的分块大小为1x3712x3712。在时间维度上进行切片基本上可以读取整个文件 在所有较小的文件上循环(即使是在多个进程中)也会花费大量时间 我的目标是: 创建月度文件(约2900x3712x3712)
- netCDF文件的分块大小为1x3712x3712。在时间维度上进行切片基本上可以读取整个文件
- 在所有较小的文件上循环(即使是在多个进程中)也会花费大量时间
- 创建月度文件(约2900x3712x3712)数据点
- 优化它们以在时间维度上进行切片(chunksize为2900x1x1或在空间维度上稍微大一点)
- 这些文件应该可以通过一个时间戳(1x3712x3712)进行追加,并且这个更新过程应该不到15分钟
- 查询应该足够快:在不到一秒钟的时间内(即2900x1x1)完成一个完整的切片==>实际上没有那么多数据
- 文件最好在更新时可以被多个进程读取
- 处理历史数据(其他5000个每日文件)的时间最好少于几周
- 连接netcdf文件并重新缓存它们==>会占用太多内存和时间
- 将它们从pandas写入hdf文件(使用pytables)==>将创建一个具有巨大索引的宽表。这最终会花费太多的时间来读取,并且由于元数据的限制,需要在空间维度上平铺数据集
- 我的最后一种方法是使用h5py将它们写入hdf5文件:
import h5py
import pandas as pd
import numpy as np
def create_h5(fps):
timestamps=pd.date_range("20050101",periods=31*96,freq='15T') #Reference time period
output_fp = r'/data/test.h5'
try:
f = h5py.File(output_fp, 'a',libver='latest')
shape = 96*nodays, 3712, 3712
d = f.create_dataset('variable', shape=(1,3712,3712), maxshape=(None,3712,3712),dtype='f', compression='gzip', compression_opts=9,chunks=(1,29,29))
f.swmr_mode = True
for fp in fps:
try:
nc=Dataset(fp)
times = num2date(nc.variables['time'][:], nc.variables['time'].units)
indices=np.searchsorted(timestamps, times)
for j,time in enumerate(times):
logger.debug("File: {}, timestamp: {:%Y%m%d %H:%M}, pos: {}, new_pos: {}".format(os.path.basename(fp),time,j,indices[j]))
d.resize((indices[j]+1,shape[1],shape[2]))
d[indices[j]]=nc.variables['variable'][j:j+1]
f.flush()
finally:
nc.close()
finally:
f.close()
return output_fp
我正在使用HDF5的最新版本来拥有SWMR选项。fps参数是每日netCDF4文件的文件路径列表。它在大约2小时内创建文件(在ssd上,但我看到创建文件主要是CPU绑定的),这是可以接受的
我已经设置了压缩,以将文件大小保持在限制范围内。我做了早期的测试,发现没有的创建速度快了一点,但是切片在压缩时不会花费太多时间。H5py自动将数据集分为1x116x116块
现在的问题是:使用RAID 6设置在NAS上进行切片,切片时间维度大约需要20秒,即使它位于单个块中
我想,即使它在文件中的一个块中,因为我在一个循环中写入了所有的值,它也必须以某种方式分段(但不知道这个过程是如何工作的)。这就是为什么我尝试使用HDF5的CML工具重新打包到一个新文件中,使用相同的块,但希望重新排序值,以便查询能够以更连续的顺序读取值,但运气不佳。尽管这个过程运行了6个小时,但在查询速度上却没有起到任何作用
如果我计算正确的话,读取一个块(2976x32x32)只需要几MB(11MB未压缩,我认为只比1MB压缩多一点)。这怎么会花这么长时间?我做错了什么?如果有人能告诉我幕后到底发生了什么,我会很高兴的。区块大小的影响 在最坏的情况下,读写一个块可以被视为随机读写操作。SSD的主要优点是读取或写入小块数据的速度。HDD在执行此任务时要慢得多(可以观察到系数100),NAS甚至比HDD慢得多 因此,问题的解决方案将是更大的块大小。我的系统上的一些基准测试(CoreI5-4690) 示例1(块大小(1,29,29)=3,4KB): 结果(写入/读取): SSD:38s/54s 硬盘驱动器:40s/57s NAS:252s/823s 在第二个示例中,我将使用h5py_chache,因为我不想维护(137123712)的块。标准chunk chache大小只有1 MB,因此必须对其进行更改,以避免对chunk执行多个读/写操作。 示例2(块大小(96,58,58)=1,3 MB): 结果(写入/读取): 固态硬盘:10s/16s 硬盘驱动器:10s/16s 北美:13秒/20秒 通过最小化api调用(读取和写入较大的区块块),可以进一步提高读/写速度 我也不想提及她的压缩方法。Blosc可以实现高达1GB/s的吞吐量(CPU瓶颈)。gzip速度较慢,但提供更好的压缩比
d = f.create_dataset('variable', shape, maxshape=(None,3712,3712),dtype='f',chunks=(96,58,58),compression='gzip', compression_opts=3)
20s/30s文件大小:101 MB
d=f.create_数据集('variable',shape,maxshape=(None,37123712),dtype='f',chunks=(96,58,58),compression='gzip',compression_opts=6)
50s/58s文件大小:87 MB
d=f.create_数据集('variable',shape,maxshape=(None,37123712),dtype='f',chunks=(96,58,58),compression='gzip',compression_opts=9)
50秒/60秒文件大小:64 MB
现在的基准是整整一个月(30天)。写入经过了一点优化,并使用(9637123712)写入
带blosc的133s/301s
432s/684s带gzip压缩选项=3
我在访问NAS上的数据时遇到了同样的问题。我希望这有助于……感谢您的见解。
import numpy as np
import tables #needed for blosc
import h5py as h5
import time
import h5py_cache as h5c
def modified_chunk_size():
File_Name_HDF5='some_Path'
Array=np.random.rand(1,3712,3712)
f = h5c.File(File_Name_HDF5, 'a',libver='latest',
chunk_cache_mem_size=6*1024**3)
f.swmr_mode = True
nodays=1
shape = 96*nodays, 3712, 3712
d = f.create_dataset('variable', shape, maxshape=(None,3712,3712),dtype='f',chunks=(96,58,58),compression=32001,compression_opts=(0, 0, 0, 0, 9, 1, 1), shuffle=False)
#Writing
t1=time.time()
for i in xrange(0,96*nodays):
d[i:i+1,:,:]=Array
f.close()
print(time.time()-t1)
#Reading
f = h5c.File(File_Name_HDF5, 'a',libver='latest', chunk_cache_mem_size=6*1024**3) #6 GB chunk chache
f.swmr_mode = True
d=f['variable']
for i in xrange(0,3712,58):
for j in xrange(0,3712,58):
A=np.copy(d[:,i:i+58,j:j+58])
print(time.time()-t1)
d = f.create_dataset('variable', shape, maxshape=(None,3712,3712),dtype='f',chunks=(96,58,58),compression='gzip', compression_opts=3)
def modified_chunk_size():
File_Name_HDF5='some_Path'
Array_R=np.random.rand(1,3712,3712)
Array=np.zeros((96,3712,3712),dtype=np.float32)
for j in xrange(0,96):
Array[j,:,:]=Array_R
f = h5.File(File_Name_HDF5, 'a',libver='latest')
f.swmr_mode = True
nodays=30
shape = 96, 3712, 3712
d = f.create_dataset('variable', shape, maxshape=(None,3712,3712),dtype='f',chunks=(96,58,58),compression=32001,compression_opts=(0, 0, 0, 0, 9, 1, 1), shuffle=False)
#Writing
t1=time.time()
for i in xrange(0,96*nodays,96):
d[i:i+96,:,:]=Array
d.resize((d.shape[0]+96,shape[1],shape[2]))
f.close()
print(time.time()-t1)
#Reading
f = h5.File(File_Name_HDF5, 'a',libver='latest')
f.swmr_mode = True
d=f['variable']
for i in xrange(0,3712,58):
for j in xrange(0,3712,58):
A=np.copy(d[:,i:i+58,j:j+58])
print(time.time()-t1)