• 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* :class:`Barrier`
32
33
34---------
35
36
37Lock
38====
39
40.. class:: Lock()
41
42   Implements a mutex lock for asyncio tasks.  Not thread-safe.
43
44   An asyncio lock can be used to guarantee exclusive access to a
45   shared resource.
46
47   The preferred way to use a Lock is an :keyword:`async with`
48   statement::
49
50       lock = asyncio.Lock()
51
52       # ... later
53       async with lock:
54           # access shared state
55
56   which is equivalent to::
57
58       lock = asyncio.Lock()
59
60       # ... later
61       await lock.acquire()
62       try:
63           # access shared state
64       finally:
65           lock.release()
66
67   .. versionchanged:: 3.10
68      Removed the *loop* parameter.
69
70   .. coroutinemethod:: acquire()
71
72      Acquire the lock.
73
74      This method waits until the lock is *unlocked*, sets it to
75      *locked* and returns ``True``.
76
77      When more than one coroutine is blocked in :meth:`acquire`
78      waiting for the lock to be unlocked, only one coroutine
79      eventually proceeds.
80
81      Acquiring a lock is *fair*: the coroutine that proceeds will be
82      the first coroutine that started waiting on the lock.
83
84   .. method:: release()
85
86      Release the lock.
87
88      When the lock is *locked*, reset it to *unlocked* and return.
89
90      If the lock is *unlocked*, a :exc:`RuntimeError` is raised.
91
92   .. method:: locked()
93
94      Return ``True`` if the lock is *locked*.
95
96
97Event
98=====
99
100.. class:: Event()
101
102   An event object.  Not thread-safe.
103
104   An asyncio event can be used to notify multiple asyncio tasks
105   that some event has happened.
106
107   An Event object manages an internal flag that can be set to *true*
108   with the :meth:`~Event.set` method and reset to *false* with the
109   :meth:`clear` method.  The :meth:`~Event.wait` method blocks until the
110   flag is set to *true*.  The flag is set to *false* initially.
111
112   .. versionchanged:: 3.10
113      Removed the *loop* parameter.
114
115   .. _asyncio_example_sync_event:
116
117   Example::
118
119      async def waiter(event):
120          print('waiting for it ...')
121          await event.wait()
122          print('... got it!')
123
124      async def main():
125          # Create an Event object.
126          event = asyncio.Event()
127
128          # Spawn a Task to wait until 'event' is set.
129          waiter_task = asyncio.create_task(waiter(event))
130
131          # Sleep for 1 second and set the event.
132          await asyncio.sleep(1)
133          event.set()
134
135          # Wait until the waiter task is finished.
136          await waiter_task
137
138      asyncio.run(main())
139
140   .. coroutinemethod:: wait()
141
142      Wait until the event is set.
143
144      If the event is set, return ``True`` immediately.
145      Otherwise block until another task calls :meth:`~Event.set`.
146
147   .. method:: set()
148
149      Set the event.
150
151      All tasks waiting for event to be set will be immediately
152      awakened.
153
154   .. method:: clear()
155
156      Clear (unset) the event.
157
158      Tasks awaiting on :meth:`~Event.wait` will now block until the
159      :meth:`~Event.set` method is called again.
160
161   .. method:: is_set()
162
163      Return ``True`` if the event is set.
164
165
166Condition
167=========
168
169.. class:: Condition(lock=None)
170
171   A Condition object.  Not thread-safe.
172
173   An asyncio condition primitive can be used by a task to wait for
174   some event to happen and then get exclusive access to a shared
175   resource.
176
177   In essence, a Condition object combines the functionality
178   of an :class:`Event` and a :class:`Lock`.  It is possible to have
179   multiple Condition objects share one Lock, which allows coordinating
180   exclusive access to a shared resource between different tasks
181   interested in particular states of that shared resource.
182
183   The optional *lock* argument must be a :class:`Lock` object or
184   ``None``.  In the latter case a new Lock object is created
185   automatically.
186
187   .. versionchanged:: 3.10
188      Removed the *loop* parameter.
189
190   The preferred way to use a Condition is an :keyword:`async with`
191   statement::
192
193       cond = asyncio.Condition()
194
195       # ... later
196       async with cond:
197           await cond.wait()
198
199   which is equivalent to::
200
201       cond = asyncio.Condition()
202
203       # ... later
204       await cond.acquire()
205       try:
206           await cond.wait()
207       finally:
208           cond.release()
209
210   .. coroutinemethod:: acquire()
211
212      Acquire the underlying lock.
213
214      This method waits until the underlying lock is *unlocked*,
215      sets it to *locked* and returns ``True``.
216
217   .. method:: notify(n=1)
218
219      Wake up *n* tasks (1 by default) waiting on this
220      condition.  If fewer than *n* tasks are waiting they are all awakened.
221
222      The lock must be acquired before this method is called and
223      released shortly after.  If called with an *unlocked* lock
224      a :exc:`RuntimeError` error is raised.
225
226   .. method:: locked()
227
228      Return ``True`` if the underlying lock is acquired.
229
230   .. method:: notify_all()
231
232      Wake up all tasks waiting on this condition.
233
234      This method acts like :meth:`notify`, but wakes up all waiting
235      tasks.
236
237      The lock must be acquired before this method is called and
238      released shortly after.  If called with an *unlocked* lock
239      a :exc:`RuntimeError` error is raised.
240
241   .. method:: release()
242
243      Release the underlying lock.
244
245      When invoked on an unlocked lock, a :exc:`RuntimeError` is
246      raised.
247
248   .. coroutinemethod:: wait()
249
250      Wait until notified.
251
252      If the calling task has not acquired the lock when this method is
253      called, a :exc:`RuntimeError` is raised.
254
255      This method releases the underlying lock, and then blocks until
256      it is awakened by a :meth:`notify` or :meth:`notify_all` call.
257      Once awakened, the Condition re-acquires its lock and this method
258      returns ``True``.
259
260      Note that a task *may* return from this call spuriously,
261      which is why the caller should always re-check the state
262      and be prepared to :meth:`~Condition.wait` again. For this reason, you may
263      prefer to use :meth:`~Condition.wait_for` instead.
264
265   .. coroutinemethod:: wait_for(predicate)
266
267      Wait until a predicate becomes *true*.
268
269      The predicate must be a callable which result will be
270      interpreted as a boolean value.  The method will repeatedly
271      :meth:`~Condition.wait` until the predicate evaluates to *true*. The final value is the
272      return value.
273
274
275Semaphore
276=========
277
278.. class:: Semaphore(value=1)
279
280   A Semaphore object.  Not thread-safe.
281
282   A semaphore manages an internal counter which is decremented by each
283   :meth:`acquire` call and incremented by each :meth:`release` call.
284   The counter can never go below zero; when :meth:`acquire` finds
285   that it is zero, it blocks, waiting until some task calls
286   :meth:`release`.
287
288   The optional *value* argument gives the initial value for the
289   internal counter (``1`` by default). If the given value is
290   less than ``0`` a :exc:`ValueError` is raised.
291
292   .. versionchanged:: 3.10
293      Removed the *loop* parameter.
294
295   The preferred way to use a Semaphore is an :keyword:`async with`
296   statement::
297
298       sem = asyncio.Semaphore(10)
299
300       # ... later
301       async with sem:
302           # work with shared resource
303
304   which is equivalent to::
305
306       sem = asyncio.Semaphore(10)
307
308       # ... later
309       await sem.acquire()
310       try:
311           # work with shared resource
312       finally:
313           sem.release()
314
315   .. coroutinemethod:: acquire()
316
317      Acquire a semaphore.
318
319      If the internal counter is greater than zero, decrement
320      it by one and return ``True`` immediately.  If it is zero, wait
321      until a :meth:`release` is called and return ``True``.
322
323   .. method:: locked()
324
325      Returns ``True`` if semaphore can not be acquired immediately.
326
327   .. method:: release()
328
329      Release a semaphore, incrementing the internal counter by one.
330      Can wake up a task waiting to acquire the semaphore.
331
332      Unlike :class:`BoundedSemaphore`, :class:`Semaphore` allows
333      making more ``release()`` calls than ``acquire()`` calls.
334
335
336BoundedSemaphore
337================
338
339.. class:: BoundedSemaphore(value=1)
340
341   A bounded semaphore object.  Not thread-safe.
342
343   Bounded Semaphore is a version of :class:`Semaphore` that raises
344   a :exc:`ValueError` in :meth:`~Semaphore.release` if it
345   increases the internal counter above the initial *value*.
346
347   .. versionchanged:: 3.10
348      Removed the *loop* parameter.
349
350
351Barrier
352=======
353
354.. class:: Barrier(parties)
355
356   A barrier object.  Not thread-safe.
357
358   A barrier is a simple synchronization primitive that allows to block until
359   *parties* number of tasks are waiting on it.
360   Tasks can wait on the :meth:`~Barrier.wait` method and would be blocked until
361   the specified number of tasks end up waiting on :meth:`~Barrier.wait`.
362   At that point all of the waiting tasks would unblock simultaneously.
363
364   :keyword:`async with` can be used as an alternative to awaiting on
365   :meth:`~Barrier.wait`.
366
367   The barrier can be reused any number of times.
368
369   .. _asyncio_example_barrier:
370
371   Example::
372
373      async def example_barrier():
374         # barrier with 3 parties
375         b = asyncio.Barrier(3)
376
377         # create 2 new waiting tasks
378         asyncio.create_task(b.wait())
379         asyncio.create_task(b.wait())
380
381         await asyncio.sleep(0)
382         print(b)
383
384         # The third .wait() call passes the barrier
385         await b.wait()
386         print(b)
387         print("barrier passed")
388
389         await asyncio.sleep(0)
390         print(b)
391
392      asyncio.run(example_barrier())
393
394   Result of this example is::
395
396      <asyncio.locks.Barrier object at 0x... [filling, waiters:2/3]>
397      <asyncio.locks.Barrier object at 0x... [draining, waiters:0/3]>
398      barrier passed
399      <asyncio.locks.Barrier object at 0x... [filling, waiters:0/3]>
400
401   .. versionadded:: 3.11
402
403   .. coroutinemethod:: wait()
404
405      Pass the barrier. When all the tasks party to the barrier have called
406      this function, they are all unblocked simultaneously.
407
408      When a waiting or blocked task in the barrier is cancelled,
409      this task exits the barrier which stays in the same state.
410      If the state of the barrier is "filling", the number of waiting task
411      decreases by 1.
412
413      The return value is an integer in the range of 0 to ``parties-1``, different
414      for each task. This can be used to select a task to do some special
415      housekeeping, e.g.::
416
417         ...
418         async with barrier as position:
419            if position == 0:
420               # Only one task prints this
421               print('End of *draining phase*')
422
423      This method may raise a :class:`BrokenBarrierError` exception if the
424      barrier is broken or reset while a task is waiting.
425      It could raise a :exc:`CancelledError` if a task is cancelled.
426
427   .. coroutinemethod:: reset()
428
429      Return the barrier to the default, empty state.  Any tasks waiting on it
430      will receive the :class:`BrokenBarrierError` exception.
431
432      If a barrier is broken it may be better to just leave it and create a new one.
433
434   .. coroutinemethod:: abort()
435
436      Put the barrier into a broken state.  This causes any active or future
437      calls to :meth:`~Barrier.wait` to fail with the :class:`BrokenBarrierError`.
438      Use this for example if one of the tasks needs to abort, to avoid infinite
439      waiting tasks.
440
441   .. attribute:: parties
442
443      The number of tasks required to pass the barrier.
444
445   .. attribute:: n_waiting
446
447      The number of tasks currently waiting in the barrier while filling.
448
449   .. attribute:: broken
450
451      A boolean that is ``True`` if the barrier is in the broken state.
452
453
454.. exception:: BrokenBarrierError
455
456   This exception, a subclass of :exc:`RuntimeError`, is raised when the
457   :class:`Barrier` object is reset or broken.
458
459---------
460
461
462.. versionchanged:: 3.9
463
464   Acquiring a lock using ``await lock`` or ``yield from lock`` and/or
465   :keyword:`with` statement (``with await lock``, ``with (yield from
466   lock)``) was removed.  Use ``async with lock`` instead.
467