xarray.open_rasterio не может открыть более ~ 400 файлов внутри понимания списка

#python #list-comprehension #geospatial #python-xarray #rasterio

#python #понимание списка #геопространственный #python-xarray #rasterio

Вопрос:

Что произошло:

при попытке открыть 14 000 файлов в понимании списка с xarray.open_rasterio помощью, цикл никогда не завершается. Цель состоит в том, чтобы открыть все эти файлы GeoTIFF, изменить размер диапазона на размер даты, сложить по дате и сохранить как .single .nc. Он может открыть менее 400 файлов без проблем в понимании списка. Это имеет место на двух разных машинах Linux.

Но когда я создаю список заранее и вместо этого использую обычный цикл for для открытия каждого файла и добавления результата в список, он завершается для всех 14000 файлов примерно за минуту, как и предполагалось. Почему существует разница в производительности / возможная ошибка при использовании понимания списка? Есть ли что-то, чего мне не хватает в производительности понимания списка python в целом?

Кроме того, я использовал команду Linux lsof , чтобы довольно быстро определить, что при понимании списка около 446 файлов оставались открытыми, пока сценарий не был завершен. Значение колебалось около 446, если я продолжал проверять lsof (в нем перечислены файлы, открытые процессом с lsof -p помощью). Похоже, что некоторые файлы не закрывались в обычное время.

Что вы ожидали: я думал, что это займет около минуты, поскольку открытие одного файла занимает около 41 миллисекунды.

Минимальный полный проверяемый пример: папка данных chirps-clipped может быть загружена здесь: https://ucsb.box.com/s/erqz20bgojhvpw2xpdbbcs17e131xxe4

 import xarray as xr
import rioxarray as rio
from pathlib import Path
from datetime import datetime
%matplotlib inline

all_scenes_f = Path('../rasters/chirps-clipped')

all_precip_paths = list(all_scenes_f.glob("*"))
# for some reason the fll value is not correct. this is the correct bad value to mask by
testf = all_precip_paths[0]
x = rio.open_rasterio(testf)
badvalue = np.unique(x.where(x != x._FillValue).sel(band=1))[0]

def chirps_path_date(path):
    _, _, year, month, day, _ = path.name.split(".")
    day = day.split("-")[0]
    return datetime(int(year), int(month), int(day))


def open_chirps(path):
    data_array = rio.open_rasterio(path) #chunks makes i lazyily executed
    data_array = data_array.sel(band=1).drop("band") # gets rid of old coordinate dimension since we need bands to have unique coord ids
    data_array["date"] = chirps_path_date(path) # makes a new coordinate
    return data_array.expand_dims({"date":1}) # makes this coordinate a dimension

### each data file is small and isn't tiled so it is not a good idea to use chunking
# https://github.com/pydata/xarray/issues/2314

import rasterio
with rasterio.open(testf) as src:
    print(src.profile)

%timeit rio.open_rasterio(testf)

### This is where the file opening bug happens
daily_chirps_arrs = [xr.open_rasterio(path) for path in all_precip_paths]
 

Что-нибудь еще, что нам нужно знать?:

Окружающая среда:

Вывод xr.show_versions()

 INSTALLED VERSIONS
------------------
commit: None
python: 3.8.5 | packaged by conda-forge | (default, Sep 16 2020, 18:01:20) 
[GCC 7.5.0]
python-bits: 64
OS: Linux
OS-release: 5.4.0-53-generic
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
LOCALE: en_US.UTF-8
libhdf5: None
libnetcdf: None

xarray: 0.16.1
pandas: 1.1.4
numpy: 1.19.1
scipy: 1.5.2
netCDF4: None
pydap: None
h5netcdf: None
h5py: None
Nio: None
zarr: None
cftime: None
nc_time_axis: None
PseudoNetCDF: None
rasterio: 1.1.6
cfgrib: None
iris: None
bottleneck: None
dask: 2.27.0
distributed: 2.30.1
matplotlib: 3.3.2
cartopy: None
seaborn: None
numbagg: None
pint: None
setuptools: 49.6.0.post20200917
pip: 20.2.3
conda: None
pytest: None
IPython: 7.18.1
sphinx: None
 

Комментарии:

1. Я подозреваю, что вы превышаете лимит открытых системных файлов — попробуйте ulimit, чтобы увидеть, решение состоит в том, чтобы закрыть файл после внесения изменений