xarray: Cannot pickle '_thread.lock' object exception after DataArray transpose and copy operations from netCDF file.
What is your issue?
I hit this issue while using rioxarray with a series of operations similar to those noted in this issue https://github.com/corteva/rioxarray/issues/614. After looking through the rioxarray
codebase a bit I was able to reproduce the issue with pure xarray
operations.
If the Dataset is opened with the default lock=True
settings, transposing a DataArray’s coordinates and then copying the DataArray results in a cannot pickle '_thread.lock' object
exception.
If the Dataset is opened with lock=False
, no error is thrown.
This sample notebook reproduces the error.
This might be user error on my part, but it would be great to have some clarification on why lock=False
is necessary here as my understanding was that this should only be necessary when using parallel write operations.
About this issue
- Original URL
- State: closed
- Created 8 months ago
- Comments: 22 (14 by maintainers)
TL;DR:
The current default of
xr.open_dataset
(netcdf4/h5netcdf) uses lazy loading which usesthreading.Lock
as default locking mechanism ifdask
is not available. The object cannot be pickled and after some computations (here.transpose
) also not (deep)-copied. The only way around is to either explicitly uselock=False
when opening files or do a.load()
or.compute()
before pickle/copy.Inspection:
Using the MCVE given here https://github.com/pydata/xarray/issues/8442#issuecomment-1841971760 I checked the types of the underlying array and how this works for transposing or not:
cache=True
inopen_dataset
(default)<class 'xarray.core.indexing.MemoryCachedArray'>
<class 'xarray.core.indexing.MemoryCachedArray'>
TypeError: cannot pickle '_thread.lock' object
in pickle<class 'xarray.core.indexing.MemoryCachedArray'>
<class 'xarray.core.indexing.LazilyVectorizedIndexedArray'>
TypeError: cannot pickle '_thread.lock' object
in deepcopycache=False
inopen_dataset
<class 'xarray.core.indexing.CopyOnWriteArray'>
<class 'xarray.core.indexing.CopyOnWriteArray'>
TypeError: cannot pickle '_thread.lock' object
in pickle<class 'xarray.core.indexing.CopyOnWriteArray'>
<class 'xarray.core.indexing.LazilyVectorizedIndexedArray'>
TypeError: cannot pickle '_thread.lock' object
in deepcopyReading with
netcdf4
andh5netcdf
backends the data is wrapped in xarray’s lazy classes See https://docs.xarray.dev/en/stable/user-guide/io.html#netcdf:and further:
There is also a mention for Pickle:
https://docs.xarray.dev/en/stable/user-guide/io.html#pickle
What to do?
The pickle issue might not be the big problem as the user is advised to load/compute before. But the copy-issue should be resolved somehow. Unfortunately I do not have an immediate solution to this. @pydata/xarray any ideas?
I believe the issue are these two default locks for HDF5 and NetCDFC: https://github.com/pydata/xarray/blob/2971994ef1dd67f44fe59e846c62b47e1e5b240b/xarray/backends/locks.py#L18
Probably the easiest way to handle this is to fork the code for SerializableLock from dask. It isn’t very complicated: https://github.com/dask/dask/blob/6f2100847e2042d459534294531e8884bef13a99/dask/utils.py#L1160
(brief message to say thanks a lot @kmuehlbauer for the excellent summary)
@kmuehlbauer for me I don’t have the environment anymore, but I suspect I probably had dask installed in it and that’s why it was working.
@kmuehlbauer I experienced the error on Windows as well as WSL.
I tried a fresh env on Linux and still got the error 🤷
Versions
Edit: From above OP also didn’t have Dask. Adding
dask-core
to my env, no more error.OK, here we go, I’ve taken
dask
out of the loop in a fresh env and can now reproduce both MCVE.Versions
No idea if it has the same underlying cause (I’m not transposing but am copying), but I do have a situation that used to work but now[^1] gives this same
cannot pickle '_thread.lock' object
error[^3]. I’ll have to see if I can make it into a minimal example. Tried downgrading some things in my environment to no avail.Edit: here’s a little example[^2] experimenting with
joblib.dump
to see when the error is raised.Versions
Also tried in an env with HDF5 1.14.3, it didn’t help.
[^1]: First noticed a month or two ago I think. [^2]: Not super related to my real case except that my case involves
joblib
. [^3]: Based on what happened later on this thread, maybe in my old env where it was working I had Dask available, for itsSerializableLock
, unlike in this new env where I was getting the error.