Какой самый эффективный способ обработки больших объемов данных с диска с использованием Python? - PullRequest
1 голос
/ 22 декабря 2010

Я писал простой скрипт на python для чтения и восстановления данных из вышедшего из строя массива RAID5, который я не смог восстановить каким-либо другим способом. Мой сценарий работает, но медленно. Мой оригинальный сценарий работал со скоростью около 80 МБ / мин. С тех пор я улучшил сценарий, и он работает со скоростью 550 МБ / мин, но это все еще кажется немного низким. Скрипт python работает на 100% процессорной мощности, поэтому он, скорее всего, загружен, а не ограничен диском, что означает, что у меня есть возможность для оптимизации. Поскольку сценарий совсем не длинный, я не могу эффективно его профилировать, поэтому я не знаю, что все это съедает. Вот мой сценарий в его нынешнем виде (или, по крайней мере, важные биты)

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 на уровне строки?) Я даже правильно обращаюсь с этим или есть лучший способ обработки огромных объемов двоичных данных?

Причина, по которой я спрашиваю, состоит в том, что я перестраиваю диск объемом 3 ТБ, и хотя он работает правильно (я могу смонтировать образ ro, зациклить и просматривать файлы), это занимает много времени. Я измерил его до середины января со старым кодом, теперь он будет работать до Рождества (так что это в порядке лучше, но все равно медленнее, чем я ожидал).

Прежде чем вы спросите, это mdadm RAID5 (размер блока 64 КБ, слева симметричный), но метаданные mdadm как-то отсутствуют, и mdadm не позволяет перенастроить RAID5 без перезаписи метаданных на диск, чего я пытаюсь избежать Во что бы то ни стало, я не хочу рисковать, что-то напутать и потерять данные, как бы отдаленно это ни было.

Ответы [ 2 ]

3 голосов
/ 22 декабря 2010
  1. map (takexor, magicpotato) - это, вероятно, лучше сделать с помощью прямой итерации, карта неэффективна, если ей нужно вызывать другой код Python AFAIK, ей нужно создавать и уничтожать 16384 фреймовых объекта для выполнения вызова и т. д.

  2. Использовать модуль массива вместо struct

  3. Если это все еще слишком медленно, скомпилируйте его с помощью Cython и добавьте несколько статических типов (что, вероятно, сделает его на 2-3 порядка быстрее)

0 голосов
/ 22 декабря 2010

Google для: широкоформатный питон. Некоторые методы, обсуждаемые в записях Python, могут быть полезны, например, отображение ввода-вывода памяти.

...