Как ускорить чтение из сжатых файлов HDF5 - PullRequest
0 голосов
/ 22 марта 2019

У меня есть несколько больших файлов HDF5, хранящихся на SSD (размер сжатого файла lzf составляет 10–15 ГБ, размер несжатого файла - 20–25 ГБ). Чтение содержимого такого файла в оперативную память для дальнейшей обработки занимает примерно 2 минуты на файл. За это время используется только одно ядро ​​(но до 100%). Таким образом, я предполагаю, что декомпрессионная часть, работающая на CPU, является узким местом, а не пропускной способностью ввода-вывода SSD.

В начале моей программы она считывает несколько файлов такого рода в оперативную память, что занимает довольно много времени. Мне нравится ускорять этот процесс, используя больше ядер и, в конечном итоге, больше оперативной памяти, пока пропускная способность ввода-вывода SSD не станет ограничивающим фактором. Машина, на которой я работаю, имеет много ресурсов (20 процессорных ядер [+ 20 HT] и 400 ГБ ОЗУ), и «потеря» ОЗУ не представляет особой проблемы, если она оправдана экономией времени.

У меня было две идеи:

1) Используйте модуль Python multiprocessing для чтения нескольких файлов в ОЗУ параллельно. Это работает в принципе, но из-за использования Pickle в multiprocessing (как указано здесь ), я достиг предела сериализации 4 ГБ:

OverflowError ('не может сериализовать объект байтов размером более 4 ГиБ').

2) Сделайте несколько процессов (используя Pool из модуля multiprocessing), откройте один и тот же файл HDF5 (используя with h5py.File('foo.h5', 'r') as h_file:), прочитайте отдельный фрагмент из него (chunk = h_file['label'][i : i + chunk_size]) и верните этот фрагмент. Собранные куски будут затем объединены. Однако это не удается с

OSError: Невозможно прочитать данные (ошибка данных обнаружена контрольной суммой Fletcher32).

Это связано с тем, что я открываю один и тот же файл в нескольких процессах (как предложено здесь )?


Итак, мой последний вопрос: как я могу быстрее прочитать содержимое файлов .h5 в основную память? Опять же: «Тратить» ОЗУ в пользу экономии времени разрешено. Содержимое должно находиться в основной памяти, поэтому обойти проблему, просто прочитав строки или дроби, не вариант. Я знаю, что могу просто хранить файлы .h5 без сжатия, но это только последний вариант, который мне нравится использовать, поскольку места на SSD недостаточно. Я предпочитаю как сжатые файлы, так и быстрое чтение (в идеале лучше использовать имеющиеся ресурсы).

Мета-информация: я использую python 3.5.2 и h5py 2.8.0.


EDIT: при чтении файла SSD работает со скоростью 72 МБ / с, что далеко от максимума. Файлы .h5 были созданы с использованием метода create_dataset h5py с опцией compression="lzf".

РЕДАКТИРОВАТЬ 2: Это (упрощенный) код, который я использую для чтения содержимого (сжатого) файла HDF5:

def opener(filename, label): # regular version
    with h5py.File(filename, 'r') as h_file:
        data = g_file[label][:]
    return data

def fast_opener(filename, label): # multiple processes version
    with h5py.File(filename, 'r') as h_file:
        length = len(h_file[label])
    pool = Pool() # multiprocessing.Pool and not multiprocessing.dummy.Pool
    args_iter = zip(
        range(0, length, 1000),
        repeat(filename),
        repeat(label),
    )
    chunks = pool.starmap(_read_chunk_at, args_iter)
    pool.close()
    pool.join()
    return np.concatenate(chunks)

def _read_chunk_at(index, filename, label):
    with h5py.File(filename, 'r') as h_file:
        data = h_file[label][index : index + 1000]
    return data

Как видите, декомпрессия выполняется прозрачно с помощью h5py.

1 Ответ

1 голос
/ 22 марта 2019

h5py обрабатывает распаковку файлов LZF через фильтр.Исходный код фильтра, реализованного на C, доступен на hithpy github здесь .Глядя на реализацию lzf_decompress, которая является функцией, вызывающей ваше узкое место, вы можете увидеть, что она не распараллелена (не знаю, если она даже распараллеливается, я оставлю это мнение людям, более знакомым с внутренним LZF).работы).

С учетом сказанного, я боюсь, что нет никакого способа просто взять ваш огромный сжатый файл и распаковать его в многопоточном режиме.Насколько я могу судить, у вас есть следующие варианты:

  • Разделить огромный файл на отдельные фрагменты с индивидуальным сжатием, распаковать параллельно каждый блок на отдельное ядро ​​(multiprocessing может помочь, но выВам нужно будет позаботиться о разделяемой памяти между процессами) и объединить все вместе после распаковки.
  • Просто используйте несжатые файлы.
...