【问题标题】:What's the most efficient way to process massive amounts of data from a disk using python?使用 python 从磁盘处理大量数据的最有效方法是什么?
【发布时间】:2011-05-29 07:08:07
【问题描述】:

我正在编写一个简单的 python 脚本来读取和重建失败的 RAID5 阵列的数据,我无法以任何其他方式重建该阵列。我的脚本正在运行,但速度很慢。我的原始脚本以大约 80MB/分钟的速度运行。我已经改进了脚本,它以 550MB/分钟的速度运行,但这似乎仍然有点低。 python 脚本位于 100% CPU,所以它似乎是 CPU 而不是磁盘受限,这意味着我有机会进行优化。因为脚本根本不是很长,所以我无法有效地分析它,所以我不知道是什么在吃掉它。这是我现在的脚本(或者至少是重要的部分)

disk0chunk = disk0.read(chunkSize)
#disk1 is missing, bad firmware
disk2chunk = disk2.read(chunkSize)
disk3chunk = disk3.read(chunkSize)
if (parityDisk % 4 == 1): #if the parity stripe is on the missing drive
  output.write(disk0chunk + disk2chunk + disk3chunk)
else: #we need to rebuild the data in disk1
  # disk0num = map(ord, disk0chunk) #inefficient, old code
  # disk2num = map(ord, disk2chunk) #inefficient, old code
  # disk3num = map(ord, disk3chunk) #inefficient, old code
  disk0num = struct.depack("16384l", disk0chunk) #more efficient new code
  disk2num = struct.depack("16384l", disk2chunk) #more efficient new code
  disk3num = struct.depack("16384l", disk3chunk) #more efficient new code
  magicpotato = zip(disk0num,disk2num,disk3num)
  disk1num = map(takexor, magicpotato)
  # disk1bytes = map(chr, disk1num) #inefficient, old code
  # disk1chunk = ''.join(disk1bytes) #inefficient, old code
  disk1chunk = struct.pack("16384l", *disk1num) #more efficient new code

  #output nonparity to based on parityDisk

def takexor(magicpotato):
  return magicpotato[0]^magicpotato[1]^magicpotato[2]

粗体表示这个巨大文本块中的实际问题:

我可以做些什么来让这更快/更好?如果什么都没想到,我能做些什么来更好地研究是什么让这件事进展缓慢? (有没有办法在每行级别分析 python?)我是否以正确的方式处理这个问题,还是有更好的方法来处理大量二进制数据?

我问的原因是我正在重建一个 3TB 驱动器,即使它工作正常(我可以正常挂载映像 ro、循环和浏览文件)它也需要很长时间。我用旧代码测量它需要到 1 月中旬,现在它要等到圣诞节(所以它方式更好,但它仍然比我预期的要慢。)

在您问之前,这是一个 mdadm RAID5(64kb 块大小,左对称),但 mdadm 元数据以某种方式丢失,并且 mdadm 不允许您在不将元数据重写到磁盘的情况下重新配置 RAID5,我试图避免这种情况不惜一切代价,我不想冒险搞砸并丢失数据,无论这种可能性多么渺茫。

【问题讨论】:

  • 您是否对您的代码进行了概要分析?我不知道每行分析,但您可以按函数分析。
  • 我只有两个功能。 :) 我还没有分析它,因为它似乎有点没用,我将有两个数据点,main 中的代码和 takexor 中的代码。当然,除非我记错了 python 的分析功能(这是可能的)
  • chunkSize 有多大?我没有看到else: output.write。这看起来确实慢得令人难以置信。磁盘开发者是缓冲的还是非缓冲的?
  • output.writes 被从示例代码中剪掉,它被一个注释取代,因为它涉及三个 if 语句,我不想​​输入它:) 输入文件是标准的 linux以类似于disk0 = open("/dev/sdc", "rb") 的行打开的块设备

标签: python optimization binary-data hard-drive raid


【解决方案1】:

谷歌搜索:widefinder python。 Python 条目中讨论的一些技术可能有用,例如内存映射 IO。

【讨论】:

    【解决方案2】:
    1. map(takexor, magicpotato) - 直接迭代可能会更好,如果它需要调用其他 python 代码 AFAIK,map 效率不高,它需要构造和销毁 16384 个帧对象来执行调用等。

    2. 使用数组模块代替结构

    3. 如果仍然太慢,请使用 cython 编译并添加一些静态类型(这可能会使其速度提高 2-3 个数量级)

    【讨论】:

    • 关于你的观点 1. 我不确定所以我查了一下,看起来 map 实际上是首选和更快的方式:wiki.python.org/moin/PythonSpeed/PerformanceTips#Loops
    • 关于你的观点2. array 模块相对于struct 有什么优势?
    • Array 将整个事物存储为 C 级数组,并提供从 python 访问它的方法,struct 创建一个 python 列表,其中每个整数都有一个单独的 int 对象(在每次迭代中分配和释放) )
    • 我的理解是,当您使用的函数是用 C 语言编写的(如示例中的 str.upper)时,如果函数是纯 python,则 map() 运行良好,如果该函数是纯 python,则必须进行过多的设置和拆卸每次迭代都要完成。
    • 非常感谢您的回复,我要去睡觉了,让这个问题逗留几个小时。
    猜你喜欢
    • 1970-01-01
    • 2018-08-30
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 2019-09-19
    • 2010-10-02
    • 2013-04-14
    相关资源
    最近更新 更多