1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
mpi4py.util.sync
----------------
.. module:: mpi4py.util.sync
:synopsis: Synchronization utilities.
.. versionadded:: 4.0.0
The :mod:`mpi4py.util.sync` module provides parallel synchronization
utilities.
Sequential execution
++++++++++++++++++++
.. autoclass:: mpi4py.util.sync.Sequential
Context manager for sequential execution within a group of MPI processes.
The implementation is based in MPI-1 point-to-point communication. A process
with rank *i* waits in a blocking receive until the previous process rank
*i-1* finish executing and signals the next rank *i* with a send.
.. automethod:: __init__
.. automethod:: __enter__
.. automethod:: __exit__
.. automethod:: begin
.. automethod:: end
Global counter
++++++++++++++
.. autoclass:: mpi4py.util.sync.Counter
Produce consecutive values within a group of MPI processes. The counter
interface is close to that of `itertools.count`.
The implementation is based in MPI-3 one-sided operations. A root process
(typically rank ``0``) holds the counter, and its value is queried and
incremented with an atomic RMA *fetch-and-add* operation.
.. automethod:: __init__
.. automethod:: __iter__
.. automethod:: __next__
.. automethod:: next
.. automethod:: free
Mutual exclusion
++++++++++++++++
.. autoclass:: mpi4py.util.sync.Mutex
Establish a critical section or mutual exclusion among MPI processes.
The mutex interface is close to that of `threading.Lock` and
`threading.RLock`, allowing the use of either recursive or non-recursive
mutual exclusion. However, a mutex should be used within a group of MPI
processes, not threads.
In non-recursive mode, the semantics of `Mutex` are somewhat different than
these of `threading.Lock`:
* Once acquired, a mutex is held and owned by a process until released.
* Trying to acquire a mutex already held raises `RuntimeError`.
* Trying to release a mutex not yet held raises `RuntimeError`.
This mutex implementation uses the scalable and fair spinlock algorithm from
[mcs-paper]_ and took inspiration from the MPI-3 RMA implementation of
[uam-book]_.
.. automethod:: __init__
.. automethod:: __enter__
.. automethod:: __exit__
.. automethod:: acquire
.. automethod:: release
.. automethod:: locked
.. automethod:: count
.. automethod:: free
.. [mcs-paper] John M. Mellor-Crummey and Michael L. Scott.
Algorithms for scalable synchronization on shared-memory multiprocessors.
ACM Transactions on Computer Systems, 9(1):21-65, February 1991.
https://doi.org/10.1145/103727.103729
.. [uam-book] William Gropp, Torsten Hoefler, Rajeev Thakur, Ewing Lusk.
Using Advanced MPI - Modern Features of the Message-Passing Interface.
Chapter 4, Section 4.7, Pages 130-131. The MIT Press, November 2014.
https://mitpress.mit.edu/9780262527637/using-advanced-mpi/
Condition variable
++++++++++++++++++
.. autoclass:: mpi4py.util.sync.Condition
A condition variable allows one or more MPI processes to wait until they are
notified by another processes.
The condition variable interface is close to that of `threading.Condition`,
allowing the use of either recursive or non-recursive mutual exclusion.
However, the condition variable should be used within a group of MPI
processes, not threads.
This condition variable implementation uses a MPI-3 RMA-based scalable and
fair circular queue algorithm to track the set of waiting processes.
.. automethod:: __init__
.. automethod:: __enter__
.. automethod:: __exit__
.. automethod:: acquire
.. automethod:: release
.. automethod:: locked
.. automethod:: wait
.. automethod:: wait_for
.. automethod:: notify
.. automethod:: notify_all
.. automethod:: free
Semaphore object
++++++++++++++++
.. autoclass:: mpi4py.util.sync.Semaphore
A semaphore object manages an internal counter which is decremented by each
`acquire()` call and incremented by each `release()` call. The internal
counter never reaches a value below zero; when `acquire()` finds that it is
zero, it blocks and waits until some other process calls `release()`.
The semaphore interface is close to that of `threading.Semaphore` and
`threading.BoundedSemaphore`, allowing the use of either bounded (default)
or unbounded semaphores. With a bounded semaphore, the internal counter
never exceeds its initial value; otherwise `release()` raises `ValueError`.
This semaphore implementation uses a global `Counter` and a `Condition`
variable to handle waiting and and notification.
.. automethod:: __init__
.. automethod:: __enter__
.. automethod:: __exit__
.. automethod:: acquire
.. automethod:: release
.. automethod:: free
Examples
++++++++
.. code-block:: python
:name: test-sync-1
:caption: :file:`test-sync-1.py`
:emphasize-lines: 2,6-9
:linenos:
from mpi4py import MPI
from mpi4py.util.sync import Counter, Sequential
comm = MPI.COMM_WORLD
counter = Counter(comm)
with Sequential(comm):
value = next(counter)
counter.free()
assert comm.rank == value
.. code-block:: python
:name: test-sync-2
:caption: :file:`test-sync-2.py`
:emphasize-lines: 2,6-11
:linenos:
from mpi4py import MPI
from mpi4py.util.sync import Counter, Mutex
comm = MPI.COMM_WORLD
mutex = Mutex(comm)
counter = Counter(comm)
with mutex:
value = next(counter)
counter.free()
mutex.free()
assert (
list(range(comm.size)) ==
sorted(comm.allgather(value))
)
.. Local variables:
.. fill-column: 79
.. End:
|