• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1.. currentmodule:: asyncio
2
3.. _asyncio-sync:
4
5==========================
6Synchronization Primitives
7==========================
8
9**Source code:** :source:`Lib/asyncio/locks.py`
10
11-----------------------------------------------
12
13asyncio synchronization primitives are designed to be similar to
14those of the :mod:`threading` module with two important caveats:
15
16* asyncio primitives are not thread-safe, therefore they should not
17  be used for OS thread synchronization (use :mod:`threading` for
18  that);
19
20* methods of these synchronization primitives do not accept the *timeout*
21  argument; use the :func:`asyncio.wait_for` function to perform
22  operations with timeouts.
23
24asyncio has the following basic synchronization primitives:
25
26* :class:`Lock`
27* :class:`Event`
28* :class:`Condition`
29* :class:`Semaphore`
30* :class:`BoundedSemaphore`
31
32
33---------
34
35
36Lock
37====
38
39.. class:: Lock()
40
41   Implements a mutex lock for asyncio tasks.  Not thread-safe.
42
43   An asyncio lock can be used to guarantee exclusive access to a
44   shared resource.
45
46   The preferred way to use a Lock is an :keyword:`async with`
47   statement::
48
49       lock = asyncio.Lock()
50
51       # ... later
52       async with lock:
53           # access shared state
54
55   which is equivalent to::
56
57       lock = asyncio.Lock()
58
59       # ... later
60       await lock.acquire()
61       try:
62           # access shared state
63       finally:
64           lock.release()
65
66   .. versionchanged:: 3.10
67      Removed the *loop* parameter.
68
69   .. coroutinemethod:: acquire()
70
71      Acquire the lock.
72
73      This method waits until the lock is *unlocked*, sets it to
74      *locked* and returns ``True``.
75
76      When more than one coroutine is blocked in :meth:`acquire`
77      waiting for the lock to be unlocked, only one coroutine
78      eventually proceeds.
79
80      Acquiring a lock is *fair*: the coroutine that proceeds will be
81      the first coroutine that started waiting on the lock.
82
83   .. method:: release()
84
85      Release the lock.
86
87      When the lock is *locked*, reset it to *unlocked* and return.
88
89      If the lock is *unlocked*, a :exc:`RuntimeError` is raised.
90
91   .. method:: locked()
92
93      Return ``True`` if the lock is *locked*.
94
95
96Event
97=====
98
99.. class:: Event()
100
101   An event object.  Not thread-safe.
102
103   An asyncio event can be used to notify multiple asyncio tasks
104   that some event has happened.
105
106   An Event object manages an internal flag that can be set to *true*
107   with the :meth:`~Event.set` method and reset to *false* with the
108   :meth:`clear` method.  The :meth:`~Event.wait` method blocks until the
109   flag is set to *true*.  The flag is set to *false* initially.
110
111   .. versionchanged:: 3.10
112      Removed the *loop* parameter.
113
114   .. _asyncio_example_sync_event:
115
116   Example::
117
118      async def waiter(event):
119          print('waiting for it ...')
120          await event.wait()
121          print('... got it!')
122
123      async def main():
124          # Create an Event object.
125          event = asyncio.Event()
126
127          # Spawn a Task to wait until 'event' is set.
128          waiter_task = asyncio.create_task(waiter(event))
129
130          # Sleep for 1 second and set the event.
131          await asyncio.sleep(1)
132          event.set()
133
134          # Wait until the waiter task is finished.
135          await waiter_task
136
137      asyncio.run(main())
138
139   .. coroutinemethod:: wait()
140
141      Wait until the event is set.
142
143      If the event is set, return ``True`` immediately.
144      Otherwise block until another task calls :meth:`~Event.set`.
145
146   .. method:: set()
147
148      Set the event.
149
150      All tasks waiting for event to be set will be immediately
151      awakened.
152
153   .. method:: clear()
154
155      Clear (unset) the event.
156
157      Tasks awaiting on :meth:`~Event.wait` will now block until the
158      :meth:`~Event.set` method is called again.
159
160   .. method:: is_set()
161
162      Return ``True`` if the event is set.
163
164
165Condition
166=========
167
168.. class:: Condition(lock=None)
169
170   A Condition object.  Not thread-safe.
171
172   An asyncio condition primitive can be used by a task to wait for
173   some event to happen and then get exclusive access to a shared
174   resource.
175
176   In essence, a Condition object combines the functionality
177   of an :class:`Event` and a :class:`Lock`.  It is possible to have
178   multiple Condition objects share one Lock, which allows coordinating
179   exclusive access to a shared resource between different tasks
180   interested in particular states of that shared resource.
181
182   The optional *lock* argument must be a :class:`Lock` object or
183   ``None``.  In the latter case a new Lock object is created
184   automatically.
185
186   .. versionchanged:: 3.10
187      Removed the *loop* parameter.
188
189   The preferred way to use a Condition is an :keyword:`async with`
190   statement::
191
192       cond = asyncio.Condition()
193
194       # ... later
195       async with cond:
196           await cond.wait()
197
198   which is equivalent to::
199
200       cond = asyncio.Condition()
201
202       # ... later
203       await cond.acquire()
204       try:
205           await cond.wait()
206       finally:
207           cond.release()
208
209   .. coroutinemethod:: acquire()
210
211      Acquire the underlying lock.
212
213      This method waits until the underlying lock is *unlocked*,
214      sets it to *locked* and returns ``True``.
215
216   .. method:: notify(n=1)
217
218      Wake up at most *n* tasks (1 by default) waiting on this
219      condition.  The method is no-op if no tasks are waiting.
220
221      The lock must be acquired before this method is called and
222      released shortly after.  If called with an *unlocked* lock
223      a :exc:`RuntimeError` error is raised.
224
225   .. method:: locked()
226
227      Return ``True`` if the underlying lock is acquired.
228
229   .. method:: notify_all()
230
231      Wake up all tasks waiting on this condition.
232
233      This method acts like :meth:`notify`, but wakes up all waiting
234      tasks.
235
236      The lock must be acquired before this method is called and
237      released shortly after.  If called with an *unlocked* lock
238      a :exc:`RuntimeError` error is raised.
239
240   .. method:: release()
241
242      Release the underlying lock.
243
244      When invoked on an unlocked lock, a :exc:`RuntimeError` is
245      raised.
246
247   .. coroutinemethod:: wait()
248
249      Wait until notified.
250
251      If the calling task has not acquired the lock when this method is
252      called, a :exc:`RuntimeError` is raised.
253
254      This method releases the underlying lock, and then blocks until
255      it is awakened by a :meth:`notify` or :meth:`notify_all` call.
256      Once awakened, the Condition re-acquires its lock and this method
257      returns ``True``.
258
259   .. coroutinemethod:: wait_for(predicate)
260
261      Wait until a predicate becomes *true*.
262
263      The predicate must be a callable which result will be
264      interpreted as a boolean value.  The final value is the
265      return value.
266
267
268Semaphore
269=========
270
271.. class:: Semaphore(value=1)
272
273   A Semaphore object.  Not thread-safe.
274
275   A semaphore manages an internal counter which is decremented by each
276   :meth:`acquire` call and incremented by each :meth:`release` call.
277   The counter can never go below zero; when :meth:`acquire` finds
278   that it is zero, it blocks, waiting until some task calls
279   :meth:`release`.
280
281   The optional *value* argument gives the initial value for the
282   internal counter (``1`` by default). If the given value is
283   less than ``0`` a :exc:`ValueError` is raised.
284
285   .. versionchanged:: 3.10
286      Removed the *loop* parameter.
287
288   The preferred way to use a Semaphore is an :keyword:`async with`
289   statement::
290
291       sem = asyncio.Semaphore(10)
292
293       # ... later
294       async with sem:
295           # work with shared resource
296
297   which is equivalent to::
298
299       sem = asyncio.Semaphore(10)
300
301       # ... later
302       await sem.acquire()
303       try:
304           # work with shared resource
305       finally:
306           sem.release()
307
308   .. coroutinemethod:: acquire()
309
310      Acquire a semaphore.
311
312      If the internal counter is greater than zero, decrement
313      it by one and return ``True`` immediately.  If it is zero, wait
314      until a :meth:`release` is called and return ``True``.
315
316   .. method:: locked()
317
318      Returns ``True`` if semaphore can not be acquired immediately.
319
320   .. method:: release()
321
322      Release a semaphore, incrementing the internal counter by one.
323      Can wake up a task waiting to acquire the semaphore.
324
325      Unlike :class:`BoundedSemaphore`, :class:`Semaphore` allows
326      making more ``release()`` calls than ``acquire()`` calls.
327
328
329BoundedSemaphore
330================
331
332.. class:: BoundedSemaphore(value=1)
333
334   A bounded semaphore object.  Not thread-safe.
335
336   Bounded Semaphore is a version of :class:`Semaphore` that raises
337   a :exc:`ValueError` in :meth:`~Semaphore.release` if it
338   increases the internal counter above the initial *value*.
339
340   .. versionchanged:: 3.10
341      Removed the *loop* parameter.
342
343---------
344
345
346.. versionchanged:: 3.9
347
348   Acquiring a lock using ``await lock`` or ``yield from lock`` and/or
349   :keyword:`with` statement (``with await lock``, ``with (yield from
350   lock)``) was removed.  Use ``async with lock`` instead.
351