1+ .. _thread-safety :
2+
13NetCDF Thread Locking
24=====================
3- Ncdata includes support for "unifying" the thread-safety mechanisms between
4- ncdata and the format packages it supports (Iris and Ncdata).
5+ Ncdata provides the :mod: `ncdata.threadlock_sharing ` module, which can ensure that all
6+ multiple relevant data-format packages use a "unified" thread-safety mechanism to
7+ prevent them disturbing each other.
58
69This concerns the safe use of the common NetCDF library by multiple threads.
710Such multi-threaded access usually occurs when your code has Dask arrays
811created from netcdf file data, which it is either computing or storing to an
912output netcdf file.
1013
11- The netCDF4 package (and the underlying C library) does not implement any
12- threadlock, neither is it thread-safe (re-entrant) by design.
13- Thus contention is possible unless controlled by the calling packages.
14- *Each * of the data-format packages (Ncdata, Iris and Xarray) defines its own
15- locking mechanism to prevent overlapping calls into the netcdf library.
16-
17- All 3 data-format packages can map variable data into Dask lazy arrays. Iris and
18- Xarray can also create delayed write operations (but ncdata currently does not).
19-
20- However, those mechanisms cannot protect an operation of that package from
21- overlapping with one in *another * package.
14+ In short, this is not needed when all your data is loaded with only **one ** of the data
15+ packages (Iris, Xarray or ncdata). The problem only occurs when you try to
16+ realise/calculate/save results which combine data loaded from a mixture of sources.
2217
23- The :mod: `ncdata.threadlock_sharing ` module can ensure that all of the relevant
24- packages use the *same * thread lock,
25- so that they can safely co-operate in parallel operations.
18+ sample code:
2619
27- sample code::
20+ .. code-block :: python
2821
2922 from ncdata.threadlock_sharing import enable_lockshare, disable_lockshare
3023 from ncdata.xarray import from_xarray
@@ -40,11 +33,49 @@ sample code::
4033
4134 disable_lockshare()
4235
43- or::
36+ ... *or * ...
37+
38+ .. code-block :: python
4439
4540 with lockshare_context(iris = True ):
4641 ncdata = NcData(source_filepath)
4742 ncdata.variables[' x' ].attributes[' units' ] = ' K'
4843 cubes = ncdata.iris.to_iris(ncdata)
4944 iris.save(cubes, output_filepath)
5045
46+
47+ Background
48+ ^^^^^^^^^^
49+ In practice, Iris, Xarray and Ncdata are all capable of scanning netCDF files and interpreting their metadata, while
50+ not reading all the core variable data contained in them.
51+
52+ This generates objects containing Dask :class: `~dask.array.Array `\s , which provide
53+ deferred access to bulk data in files, with certain key benefits :
54+
55+ * no data loading or calculation happens until needed
56+ * the work is divided into sectional "tasks", of which only some may ultimately be needed
57+ * it may be possible to perform multiple sections of calculation (including data fetch) in parallel
58+ * it may be possible to localise operations (fetch or calculate) near to data distributed across a cluster
59+
60+ Usually, the most efficient parallelisation of array operations is by multi-threading, since that can use memory
61+ sharing of large data arrays in memory.
62+
63+ However, the python netCDF4 library (and the underlying C library) is not threadsafe
64+ (re-entrant) by design, neither does it implement any thread locking itself, therefore
65+ the “netcdf fetch” call in each input operation must be guarded by a mutex.
66+ Thus, contention is possible unless controlled by the calling packages.
67+
68+ Each of Xarray, Iris and ncdata create input data tasks to fetch sections of data from
69+ the input files. Each uses a mutex lock around netcdf accesses in those tasks, to stop
70+ them accessing the netCDF4 interface at the same time as any of the others.
71+
72+ This works beautifully until ncdata connects (for example) lazy data loaded *with Iris *
73+ with lazy data loaded *from Xarray *. These would then unfortunately each be using their
74+ own *separate * mutexes to protect the same netcdf library. So, if we then attempt to
75+ calculate or save the result, which combines data from both sources, we could get
76+ sporadic and unpredictable system-level errors, even a core-dump type failure.
77+
78+ So, the function of :mod: `ncdata.threadlock_sharing ` is to connect the thread-locking
79+ schemes of the separate libraries, so that they cannot accidentally overlap an access
80+ call in a different thread *from the other package *, just as they already cannot
81+ overlap *one of their own *.
0 commit comments