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 at most *n* tasks (1 by default) waiting on this 220 condition. The method is no-op if no tasks are waiting. 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 .. coroutinemethod:: wait_for(predicate) 261 262 Wait until a predicate becomes *true*. 263 264 The predicate must be a callable which result will be 265 interpreted as a boolean value. The final value is the 266 return value. 267 268 269Semaphore 270========= 271 272.. class:: Semaphore(value=1) 273 274 A Semaphore object. Not thread-safe. 275 276 A semaphore manages an internal counter which is decremented by each 277 :meth:`acquire` call and incremented by each :meth:`release` call. 278 The counter can never go below zero; when :meth:`acquire` finds 279 that it is zero, it blocks, waiting until some task calls 280 :meth:`release`. 281 282 The optional *value* argument gives the initial value for the 283 internal counter (``1`` by default). If the given value is 284 less than ``0`` a :exc:`ValueError` is raised. 285 286 .. versionchanged:: 3.10 287 Removed the *loop* parameter. 288 289 The preferred way to use a Semaphore is an :keyword:`async with` 290 statement:: 291 292 sem = asyncio.Semaphore(10) 293 294 # ... later 295 async with sem: 296 # work with shared resource 297 298 which is equivalent to:: 299 300 sem = asyncio.Semaphore(10) 301 302 # ... later 303 await sem.acquire() 304 try: 305 # work with shared resource 306 finally: 307 sem.release() 308 309 .. coroutinemethod:: acquire() 310 311 Acquire a semaphore. 312 313 If the internal counter is greater than zero, decrement 314 it by one and return ``True`` immediately. If it is zero, wait 315 until a :meth:`release` is called and return ``True``. 316 317 .. method:: locked() 318 319 Returns ``True`` if semaphore can not be acquired immediately. 320 321 .. method:: release() 322 323 Release a semaphore, incrementing the internal counter by one. 324 Can wake up a task waiting to acquire the semaphore. 325 326 Unlike :class:`BoundedSemaphore`, :class:`Semaphore` allows 327 making more ``release()`` calls than ``acquire()`` calls. 328 329 330BoundedSemaphore 331================ 332 333.. class:: BoundedSemaphore(value=1) 334 335 A bounded semaphore object. Not thread-safe. 336 337 Bounded Semaphore is a version of :class:`Semaphore` that raises 338 a :exc:`ValueError` in :meth:`~Semaphore.release` if it 339 increases the internal counter above the initial *value*. 340 341 .. versionchanged:: 3.10 342 Removed the *loop* parameter. 343 344 345Barrier 346======= 347 348.. class:: Barrier(parties) 349 350 A barrier object. Not thread-safe. 351 352 A barrier is a simple synchronization primitive that allows to block until 353 *parties* number of tasks are waiting on it. 354 Tasks can wait on the :meth:`~Barrier.wait` method and would be blocked until 355 the specified number of tasks end up waiting on :meth:`~Barrier.wait`. 356 At that point all of the waiting tasks would unblock simultaneously. 357 358 :keyword:`async with` can be used as an alternative to awaiting on 359 :meth:`~Barrier.wait`. 360 361 The barrier can be reused any number of times. 362 363 .. _asyncio_example_barrier: 364 365 Example:: 366 367 async def example_barrier(): 368 # barrier with 3 parties 369 b = asyncio.Barrier(3) 370 371 # create 2 new waiting tasks 372 asyncio.create_task(b.wait()) 373 asyncio.create_task(b.wait()) 374 375 await asyncio.sleep(0) 376 print(b) 377 378 # The third .wait() call passes the barrier 379 await b.wait() 380 print(b) 381 print("barrier passed") 382 383 await asyncio.sleep(0) 384 print(b) 385 386 asyncio.run(example_barrier()) 387 388 Result of this example is:: 389 390 <asyncio.locks.Barrier object at 0x... [filling, waiters:2/3]> 391 <asyncio.locks.Barrier object at 0x... [draining, waiters:0/3]> 392 barrier passed 393 <asyncio.locks.Barrier object at 0x... [filling, waiters:0/3]> 394 395 .. versionadded:: 3.11 396 397 .. coroutinemethod:: wait() 398 399 Pass the barrier. When all the tasks party to the barrier have called 400 this function, they are all unblocked simultaneously. 401 402 When a waiting or blocked task in the barrier is cancelled, 403 this task exits the barrier which stays in the same state. 404 If the state of the barrier is "filling", the number of waiting task 405 decreases by 1. 406 407 The return value is an integer in the range of 0 to ``parties-1``, different 408 for each task. This can be used to select a task to do some special 409 housekeeping, e.g.:: 410 411 ... 412 async with barrier as position: 413 if position == 0: 414 # Only one task prints this 415 print('End of *draining phase*') 416 417 This method may raise a :class:`BrokenBarrierError` exception if the 418 barrier is broken or reset while a task is waiting. 419 It could raise a :exc:`CancelledError` if a task is cancelled. 420 421 .. coroutinemethod:: reset() 422 423 Return the barrier to the default, empty state. Any tasks waiting on it 424 will receive the :class:`BrokenBarrierError` exception. 425 426 If a barrier is broken it may be better to just leave it and create a new one. 427 428 .. coroutinemethod:: abort() 429 430 Put the barrier into a broken state. This causes any active or future 431 calls to :meth:`wait` to fail with the :class:`BrokenBarrierError`. 432 Use this for example if one of the tasks needs to abort, to avoid infinite 433 waiting tasks. 434 435 .. attribute:: parties 436 437 The number of tasks required to pass the barrier. 438 439 .. attribute:: n_waiting 440 441 The number of tasks currently waiting in the barrier while filling. 442 443 .. attribute:: broken 444 445 A boolean that is ``True`` if the barrier is in the broken state. 446 447 448.. exception:: BrokenBarrierError 449 450 This exception, a subclass of :exc:`RuntimeError`, is raised when the 451 :class:`Barrier` object is reset or broken. 452 453--------- 454 455 456.. versionchanged:: 3.9 457 458 Acquiring a lock using ``await lock`` or ``yield from lock`` and/or 459 :keyword:`with` statement (``with await lock``, ``with (yield from 460 lock)``) was removed. Use ``async with lock`` instead. 461