【发布时间】:2018-09-17 00:04:45
【问题描述】:
我有一个使用 netcdf4.Dataset(fn, mode=a) 每 5 分钟增长一个 NetCDF 文件 fn 的进程。我还有一个使用xarray.Dataset 的NetCDF 文件的散景服务器可视化(我想保留它,因为它很方便)。
问题是 NetCDF-update-process 在尝试将新数据添加到 fn 时失败,如果它在我的散景服务器进程中通过
ds = xarray.open_dataset(fn)
如果我使用选项autoclose
ds = xarray.open_dataset(fn, autoclose=True)
当 ds 在散景服务器应用程序中“打开”时使用其他进程更新 fn 可以正常工作,但是从 fn 提取时间片的散景图的更新变得非常滞后。
我的问题是:在使用xarray.Dataset时,是否有其他方法可以释放NetCDF文件的锁?
我不在乎 xarray.Dataset 的形状是否仅在重新加载整个散景服务器应用程序后才会持续更新。
谢谢!
这是一个最小的工作示例:
把它放到一个文件中并让它运行:
import time
from datetime import datetime
import numpy as np
import netCDF4
fn = 'my_growing_file.nc'
with netCDF4.Dataset(fn, 'w') as nc_fh:
# create dimensions
nc_fh.createDimension('x', 90)
nc_fh.createDimension('y', 90)
nc_fh.createDimension('time', None)
# create variables
nc_fh.createVariable('x', 'f8', ('x'))
nc_fh.createVariable('y', 'f8', ('y'))
nc_fh.createVariable('time', 'f8', ('time'))
nc_fh.createVariable('rainfall_amount',
'i2',
('time', 'y', 'x'),
zlib=False,
complevel=0,
fill_value=-9999,
chunksizes=(1, 90, 90))
nc_fh['rainfall_amount'].scale_factor = 0.1
nc_fh['rainfall_amount'].add_offset = 0
nc_fh.set_auto_maskandscale(True)
# variable attributes
nc_fh['time'].long_name = 'Time'
nc_fh['time'].standard_name = 'time'
nc_fh['time'].units = 'hours since 2000-01-01 00:50:00.0'
nc_fh['time'].calendar = 'standard'
for i in range(1000):
with netCDF4.Dataset(fn, 'a') as nc_fh:
current_length = len(nc_fh['time'])
print('Appending to NetCDF file {}'.format(fn))
print(' length of time vector: {}'.format(current_length))
if current_length > 0:
last_time_stamp = netCDF4.num2date(
nc_fh['time'][-1],
units=nc_fh['time'].units,
calendar=nc_fh['time'].calendar)
print(' last time stamp in NetCDF: {}'.format(str(last_time_stamp)))
else:
last_time_stamp = '1900-01-01'
print(' empty file, starting from scratch')
nc_fh['time'][i] = netCDF4.date2num(
datetime.utcnow(),
units=nc_fh['time'].units,
calendar=nc_fh['time'].calendar)
nc_fh['rainfall_amount'][i, :, :] = np.random.rand(90, 90)
print('Sleeping...\n')
time.sleep(3)
然后,转到例如IPython 并通过以下方式打开不断增长的文件:
ds = xr.open_dataset('my_growing_file.nc')
这将导致附加到 NetCDF 的进程失败,输出如下:
Appending to NetCDF file my_growing_file.nc
length of time vector: 0
empty file, starting from scratch
Sleeping...
Appending to NetCDF file my_growing_file.nc
length of time vector: 1
last time stamp in NetCDF: 2018-04-12 08:52:39.145999
Sleeping...
Appending to NetCDF file my_growing_file.nc
length of time vector: 2
last time stamp in NetCDF: 2018-04-12 08:52:42.159254
Sleeping...
Appending to NetCDF file my_growing_file.nc
length of time vector: 3
last time stamp in NetCDF: 2018-04-12 08:52:45.169516
Sleeping...
---------------------------------------------------------------------------
IOError Traceback (most recent call last)
<ipython-input-17-9950ca2e53a6> in <module>()
37
38 for i in range(1000):
---> 39 with netCDF4.Dataset(fn, 'a') as nc_fh:
40 current_length = len(nc_fh['time'])
41
netCDF4/_netCDF4.pyx in netCDF4._netCDF4.Dataset.__init__()
netCDF4/_netCDF4.pyx in netCDF4._netCDF4._ensure_nc_success()
IOError: [Errno -101] NetCDF: HDF error: 'my_growing_file.nc'
如果使用
ds = xr.open_dataset('my_growing_file.nc', autoclose=True)
没有错误,但是通过xarray 的访问时间当然会变慢,这正是我的问题,因为我的仪表板可视化变得非常滞后。
我可以理解这可能不是xarray 的预期用途,如果需要,我将回退到netCDF4 提供的较低级别的接口(希望它支持并发文件访问,至少对于读取) ),但为了方便起见,我想保留xarray。
【问题讨论】:
-
您能否添加一个最小、完整和可验证的示例 (stackoverflow.com/help/mcve)?我怀疑您的问题的答案将取决于您的具体实施。例如,不清楚您是否在任何时候调用
ds.close()。 -
@jhamman 感谢您的快速回复。我将使用 MCVE 更新我的帖子,但由于其他职责,这可能需要几天时间。我认为可能有一个简单的确定答案,例如“永远不要写入以 xarray.Dataset` 形式打开的文件。
-
我用
netcdf4和h5py玩了一下。使用netcdf4我没有成功在两个进程中同时打开一个文件。对于h5py.File,有一个标志swmr(single writer multiple reader) 专门表示我可以读取,而另一个进程保持打开文件以进行写入。这可行,尽管与我的示例略有不同,因为增长的文件必须始终保持打开状态,并且不能在 for 循环中关闭和重新打开。我错过了什么,还是使用h5py的唯一方法?
标签: python concurrency netcdf python-xarray