Чтение двоичного файла в Python: для чтения определенных байтов требуется очень много времени

это очень странно

Я читаю некоторые (по общему признанию, очень большие: ~ 2 ГБ каждый) двоичные файлы, используя библиотеки numpy в Python. Я использую:

thingy = np.fromfile(fileObject, np.int16, 1)

метод. Это прямо в середине вложенного цикла — я делаю этот цикл 4096 раз на «канал», и этот цикл «канал» 9 раз для каждого «приемника», и этот цикл «приемник» 4 раза (всего 9 каналов). на приемник, которых 4!). Это для каждого «блока», из которых около 3600 на файл.

Как видите, это очень многократно, и я знаю, что это займет много времени, но это заняло НАМНОГО больше времени, чем я ожидал — в среднем 8,5 секунд на «блок».

Я провел несколько тестов, используя time.clock() и т. д., и обнаружил, что все идет так быстро, как должно быть, за исключением примерно 1 или 2 выборок на «блок» (то есть 1 или 2 в 4096 * 9 * 4), где казалось бы «застрять» на несколько секунд. Теперь это должен быть случай возврата простого int16 из двоичного файла, а не совсем то, что должно занимать секунды ... почему это застревает?

Из бенчмаркинга я обнаружил, что он каждый раз застревал в ОДНОМ и том же месте (блок 2, приемник 8, канал 3, образец 1085 был одним из них, для записи!), и он застревал там примерно на одно и то же время. время каждого запуска.

Любые идеи?!

Спасибо,

Дункан


person Duncan Tait    schedule 15.02.2010    source источник
comment
Я полагаю, считать с 0?   -  person Craig McQueen    schedule 15.02.2010
comment
Да, так что приемники 0-3, каналы 0-7, образцы 0-4095   -  person Duncan Tait    schedule 15.02.2010
comment
Проблема с чем-то вроде fromfile() заключается в том, что он не может заранее знать, сколько места нужно выделить, поэтому с действительно большими файлами вы можете облажаться. См. мой ответ и некоторые из следующих комментариев в stackoverflow.com/questions/1896674/ для возможных идей о том, как с этим справиться, и основной проблемы.   -  person Peter Hansen    schedule 16.02.2010
comment
Питер, спасибо за это, дело в том, что я не пытаюсь хранить все одновременно ни в одном из них. Я просто читаю управляемые блоки данных (максимум ~ 2 МБ), вычисляю с ними что-то, записываю результат в файл, а затем повторяю это. Кажется, что, возможно, тот, с которым я закончил, не утилизируется / не собирается мусор. Я попробую некоторые из этих решений завтра, когда вернусь на работу.   -  person Duncan Tait    schedule 16.02.2010
comment
те, с которыми я закончил, не удаляются - попробуйте del xx, когда закончите? может гс раньше, может нет   -  person denis    schedule 19.02.2010
comment
Да, del сработал очень хорошо, спасибо!   -  person Duncan Tait    schedule 23.02.2010
comment
@Duncan Tait, причина, по которой я указал на эту проблему, заключается в том, что использование fromfile() означает, что массив должен каким-то образом расти, что приводит к большой активности памяти. Если вы заранее знаете размер, который вам нужен (который вам кажется), вы можете предварительно выделить, загрузить намного быстрее и избежать перегрузки памяти, которая кажется вашей основной проблемой. Я думаю, что fromfile() может быть, как и print и input(), предназначено для упрощенных ситуаций.   -  person Peter Hansen    schedule 27.02.2010


Ответы (3)


Хотя трудно сказать без какого-либо воспроизводимого образца, это звучит как проблема с буферизацией. Первая часть буферизуется, и пока вы не достигнете конца буфера, она выполняется быстро; затем он замедляется до тех пор, пока не будет заполнен следующий буфер, и так далее.

person Max Shawabkeh    schedule 15.02.2010
comment
Да, это звучит вероятно, вы знаете, как я мог бы проверить это? Или каков вероятный размер буфера? - person Duncan Tait; 15.02.2010
comment
Что ж, одна вещь, чтобы хотя бы определить, ближе ли я или gnibbler к решению, — это запустить его и мгновенно отбросить результаты. Если замедление все еще происходит, это, скорее всего, проблема с буферизацией. Тогда, возможно, посмотрите, изменит ли что-нибудь чтение вручную вместо numpy. - person Max Shawabkeh; 15.02.2010
comment
Конечно, извините, что продолжаю задавать новые вопросы, но как «выбросить» объект в Python? Я пытался узнать об утилизации и т. Д. В течение многих лет, но нигде не могу найти. - person Duncan Tait; 15.02.2010
comment
Вы можете использовать gc.collect() (docs.python.org/library/gc.html), чтобы форсировать сборку мусора, но я имел в виду просто чтение, а не присвоение результата чему-либо. - person Max Shawabkeh; 15.02.2010
comment
Другой способ проверить, вызвано ли это буферизацией файла, — изменить размер буфера в функции open() файла. По умолчанию используется размер ОС по умолчанию. Посмотрите, изменится ли его изменение в том месте, где происходит пауза. Н.Б. Настройка размера буфера работает не на всех ОС — см. документацию. - person Dave Kirby; 15.02.2010
comment
Макс С: Возможно, вы правы, проблема практически исчезает, когда я не выделяю экземпляр (созданный для хранения всех данных) ни для чего, хотя он по-прежнему выполняет всю обработку. Есть ли способ узнать, насколько велик объект/список в памяти? Клянусь, он не должен быть таким большим, максимум 2 МБ, возможно, меньше 1 МБ, это действительно не должно быть проблемой, если это ... - person Duncan Tait; 17.02.2010
comment
Python имеет довольно большие накладные расходы на память, когда у вас много мелких объектов. На моей 64-битной машине пустая строка занимает 40 байт, но каждый дополнительный символ занимает только один байт. Подробнее см. в этом ответе: большие словари в памяти"> stackoverflow.com/questions/2211965/ - person Max Shawabkeh; 17.02.2010

Где вы храните результаты? Когда списки/слова/что-то еще становятся очень большими, может возникнуть заметная задержка, когда их нужно перераспределить и изменить размер.

person John La Rooy    schedule 15.02.2010
comment
Ну, по сути, все они хранятся в списках внутри списков, а затем весь набор данных (на «блок») сохраняется в экземпляре класса вместе с информацией заголовка. Хотя на самом деле это не должно быть больше мегабайта... Разве Python не избавляется от списков? Могу ли я заставить его сделать это? - person Duncan Tait; 15.02.2010

Может быть, для списков используется сборка мусора?

Добавлено: это забавные данные или блочные? Что произойдет, если вы прочитаете блоки в случайном порядке, по строкам

r = range(4096)
random.shuffle(r)  # inplace
for blockno in r:
    file.seek( blockno * ... )
    ...
person denis    schedule 15.02.2010