h5py 不遵守分块规范?

2024-03-03

问题: 我有现有的 netCDF4 文件(大约 5000 个)(通常形状为 96x3712x3712)数据点(float32)。这些文件的第一维是时间(每天一个文件),第二维和第三维是空间维。 目前,在第一维上制作切片(即使是部分切片)会花费大量时间,原因如下:

  • netCDF 文件以 1x3712x3712 的块大小进行分块。在时间维度上切片基本上会读取整个文件。
  • 对所有较小的文件进行循环(即使在多个进程中)也将花费大量时间。

My goal:

  • 创建每月文件(约2900x3712x3712)数据点
  • 优化它们以在时间维度上进行切片(块大小为 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 工具将 h5repack 放入新文件中,使用相同的块,但希望对值重新排序,以便查询能够以更连续的顺序读取值,但没有运气。尽管这个过程运行了 6 个小时,但它对查询速度没有任何影响。

如果我的计算正确,读取一个块 (2976x32x32) 仅几 MB 大(未压缩 11MB,我认为压缩后仅略多于 1MB)。怎么会花这么长时间?我究竟做错了什么?如果有人能够揭示幕后实际发生的事情,我会很高兴......


块大小的影响

在最坏的情况下,读取和写入一个块可以被视为随机读/写操作。 SSD 的主要优点是读取或写入小数据块的速度。 HDD 在执行此任务时要慢得多(可以观察到 100 倍),NAS 甚至可能比 HDD 慢得多。

所以问题的解决方案将是更大的块大小。我的系统(Core i5-4690)上的一些基准测试。

示例_1(块大小 (1,29,29)=3,4 kB):

import numpy as np
import tables #needed for blosc
import h5py as h5
import time
import h5py_cache as h5c

def original_chunk_size():
    File_Name_HDF5='some_Path'
    #Array=np.zeros((1,3712,3712),dtype=np.float32)
    Array=np.random.rand(96,3712,3712)

    f = h5.File(File_Name_HDF5, 'a',libver='latest')
    f.swmr_mode = True
    nodays=1

    shape = 96*nodays, 3712, 3712
    d = f.create_dataset('variable', shape, maxshape=(None,3712,3712),dtype='f',chunks=(1,29,29),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 = h5.File(File_Name_HDF5, 'a',libver='latest')
    f.swmr_mode = True
    d=f['variable']

    for i in xrange(0,3712,29):
        for j in xrange(0,3712,29):
            A=np.copy(d[:,i:i+29,j:j+29])

    print(time.time()-t1)

结果(写/读):

固态硬盘:38s/54s

硬盘:40s/57s

网络存储:252s/823s

在第二个示例中,我将使用 h5py_chache 因为我不想继续提供 (1,3712,3712) 块。标准 chunk-chache-size 只有 1 MB,因此必须更改它,以避免对块进行多次读/写操作。https://pypi.python.org/pypi/h5py-cache/1.0 https://pypi.python.org/pypi/h5py-cache/1.0

示例_2(块大小 (96,58,58)=1,3 MB):

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)

结果(写/读):

固态硬盘:10秒/16秒

硬盘:10秒/16秒

网络存储: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)

20秒/30秒文件大小:101 MB

d = f.create_dataset('变量', shape, maxshape=(无,3712,3712),dtype='f',块=(96,58,58),压缩='gzip',compression_opts=6)

50秒/58秒文件大小:87 MB

d = f.create_dataset('变量', shape, maxshape=(无,3712,3712),dtype='f',块=(96,58,58),压缩='gzip',compression_opts=9)

50秒/60秒文件大小:64 MB

现在是整个月(30 天)的基准。写法有点优化,写成(96,3712, 3712)。

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)

133s/301s 带 blosc

432s/684s,gzip compression_opts=3

我在访问 NAS 上的数据时遇到了同样的问题。我希望这有帮助...

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

h5py 不遵守分块规范? 的相关文章

随机推荐

  • GAE - 部署错误:“AttributeError:无法设置属性”

    当我尝试部署我的应用程序时 出现以下错误 Starting update of app flyingbat123 version 0 1 Getting current resource limits Password for avigma
  • Prestashop 送货时选择隐藏/显示付款方式

    我试图弄清楚如何在选择送货方式时显示 隐藏付款方式 我尝试了几个解决方案 但它对我不起作用 其中之一是这个
  • 如何在Flutter中像Youtube一样显示之前的时间

    我正在编写一个 flutter 应用程序来克隆一些 Youtube 功能Youtube API V3 该应用程序获取字符串形式的视频时间戳来自 YouTube 视频 API 每个时间戳都具有以下格式 YYYY MM DDTHH MM SSZ
  • 如何计算新点位于 Voronoi 图的哪个位置?

    我写了一个小脚本来显示 voronoi 图M点来自本教程 https docs scipy org doc scipy 0 18 1 reference generated scipy spatial Voronoi html I use
  • 如何获取 Xamarin.Android 的 Mono VM 的堆快照?

    背景 我正在尝试追踪 Xamarin Android 应用程序中的内存泄漏 使用 DDMS 和 Eclipse Memory Profiler 我能够查看哪些对象处于活动状态 当试图跟踪是什么让它们保持活力时 GC Root 我只看到 本机
  • 如何删除前导和尾随空格?

    我在用着awk gsub t t print in txt gt out txt删除前导和尾随空格 问题是输出文件实际上有尾随空格 所有行的长度相同 它们都用空格填充 我缺少什么 UPDATE 1 该问题可能是由于尾随空格不是 正常 空格而
  • Nuxt,转换不适用于子路由(使用 NuxtChild 显示)

    我无法为我的子路线进行转换 我有以下页面 pages child id vue child vue index vue 在索引和任何子路由之间导航都会触发转换 但是当从一个子路由导航到另一子路由时 不会发生转换 注意有静态路由 child和
  • extern 与 c 中变量的全局定义

    我有以下我感兴趣的源代码 include
  • 从 XML 结束标记填充数组

    我正在尝试创建一个字段名称数组 以便稍后在脚本中使用 正则表达式让我大吃一惊 我已经很久没有写代码了 字段名称嵌入在 XML 标记中 因此我想可以从第一行数据的结束标记中提取它们 我看不到如何正确填充数组 任何人都可以为我提供一些启示吗 m
  • 万向节锁是怎么发生的?

    所以我在网上搜索 我在想象如何 发生万向节锁定 根据我所看到的 当两个或多个轴对齐失去一定的自由度时就会发生这种情况 但我无法想象这些轴将如何开始对齐 我的意思是 当我绕 x 轴旋转对象时 例如 y 轴和 z 轴是否不会随 X 轴旋转以保持
  • 使用 PyQt5 将 qDebug 输出重定向到文件

    我使用 python2 7 Qt5 5 和 PyQt5 实现了一个应用程序 我使用Python记录器工作logging 模块 日志消息都发送到 stderr 和日志文件 但是 Qt 日志消息仅出现在 stderr 中 我找不到将它们重定向到
  • 带有标记和线条的传单

    我将 leafletjs 与 geojson 一起使用 但我无法同时使用标记绘制折线 所以我的解决方案是先绘制折线 然后添加标记 我认为这不是一个好的方法 那么还有其他解决方案吗 这是我的代码 function DrawLine mymap
  • SSRS独特的查找集函数

    我在用着Join Lookupset 查找返回序列号的唯一组值 这是我的功能 Join LookupSet Fields itemId Value Fields UseByDate Value Fields rackId Value Fie
  • Python:如何使用 BeautifulSoup 模拟点击

    我不想使用 selenium 因为我不想打开任何浏览器 该按钮会触发 Javascript 方法来更改页面中的某些内容 我想模拟按钮单击 以便我可以从中获取 输出 示例 不是按钮实际执行的操作 我输入一个名字 例如 John 按下按钮 它会
  • 如何在 Action 类之外将错误消息从 Struts2 发布到 HTML

    我有一个注册程序 当我在数据库中插入一条记录时 我将实例化一个类并调用该方法insert 当我插入相同的记录时 当然会出现重复数据错误和大量错误消息 我想捕捉它try and catch 我能做到 但是 我不知道如何将消息显示到 JSP 据
  • 提高 jQuery 模板性能

    Update 显然 jQuery 模板可以被编译 并且它有助于提高模板的性能if 语句 shown here http jsperf com complex template vs concat 4 但如图所示here http jsper
  • MFC> 将对话框连接到对话框类

    我在现有的资源文件中定义了一个新对话框及其控件 我还创建了一个新文件 它将处理从此对话框生成的事件 但我不确定如何连接这两者 是声明enum IDD IDD NEW DIALOG 连接两者所需的一切 或者我们应该添加一些其他声明 在 MFC
  • 网络调用 /.well-known/openid-configuration/ 和 /.well-known/openid-configuration/jwks

    I have 身份服务器4 具有 OpenId Connect 和混合流的 Mvc 应用程序 WebApi应用程序 假设用户已经获得带有 id token 和访问令牌的 cookie 然后他从 mvc 应用程序调用一个操作 var clie
  • 从列表列表创建 pandas 数据框,但有不同的分隔符

    我有一个列表列表 1 Toy Story 1995 Animation Children s Comedy 2 Jumanji 1995 Adventure Children s Fantasy 3 Grumpier Old Men 199
  • h5py 不遵守分块规范?

    问题 我有现有的 netCDF4 文件 大约 5000 个 通常形状为 96x3712x3712 数据点 float32 这些文件的第一维是时间 每天一个文件 第二维和第三维是空间维 目前 在第一维上制作切片 即使是部分切片 会花费大量时间