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