Обработка очень больших файлов netCDF на python
Я пытаюсь работать с данными из очень больших файлов netCDF (~ 400 Gb каждый). Каждый файл имеет несколько переменных, все намного больше, чем системная память (например, 180 ГБ против 32 ГБ ОЗУ). Я пытаюсь использовать numpy и netCDF4-python делать некоторые операции над этими переменными, копируя срез за раз и работая на этом срезе. К сожалению, на самом деле требуется очень много времени, чтобы прочитать каждый кусочек, который убивает производительность.
Например, одна из переменных - это массив формы (500, 500, 450, 300)
. Я хочу работать с срезом [:,:,0]
, поэтому я делаю следующее:
import netCDF4 as nc
f = nc.Dataset('myfile.ncdf','r+')
myvar = f.variables['myvar']
myslice = myvar[:,:,0]
Но последний шаг занимает очень много времени (~ 5 минут в моей системе). Если, например, я сохранил переменную формы (500, 500, 300)
в файле netcdf, то операция чтения того же размера займет всего несколько секунд.
Есть ли способ ускорить это? Очевидным путем было бы преобразование массива таким образом, чтобы индексы, которые я выбираю, выходили первым. Но в таком большом файле это невозможно сделать в памяти, и кажется еще медленнее попытаться это сделать, если простая операция уже занимает много времени. Мне бы хотелось, это быстрый способ прочитать фрагмент файла netcdf, в соответствии с функцией get_vara интерфейса Fortran. Или какой-то способ эффективного переноса массива.
Ответы
Ответ 1
Вы можете переместить переменные netCDF слишком большими, чтобы они соответствовали памяти, используя утилиту nccopy, которая описана здесь:
http://www.unidata.ucar.edu/netcdf/docs/guide_nccopy.html
Идея состоит в том, чтобы "переписать" файл, указав, какие формы кусков (многомерные плитки)
вы хотите переменные. Вы можете указать, сколько памяти использовать в качестве буфера и сколько
использовать для кеш-памяти, но не ясно, как оптимально использовать память между этими видами использования, поэтому вы
возможно, придется просто попробовать несколько примеров и время их. Вместо того, чтобы полностью транспонировать переменную,
вы, вероятно, захотите "частично перенести" его, указав куски, у которых много данных вдоль
2 больших размера вашего среза и имеют только несколько значений по другим параметрам.
Ответ 2
Это комментарий, а не ответ, но я не могу прокомментировать это, извините.
Я понимаю, что вы хотите обработать myvar[:,:,i]
, i
в range(450)
. В этом случае вы будете делать что-то вроде:
for i in range(450):
myslice = myvar[:,:,i]
do_something(slice)
и узкое место находится в доступе к myslice = myvar[:,:,i]
. Вы пытались сравнить, сколько времени требуется для доступа к moreslices = myvar[:,:,0:n]
? Это будут данные contiguos, и, возможно, вы сможете сэкономить время. Вы бы выбрали n
размером с памятью, а затем обработали следующий фрагмент данных moreslices = myvar[:,:,n:2n]
и т.д.