mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 11:23:31 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			335 lines
		
	
	
	
		
			8.5 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			335 lines
		
	
	
	
		
			8.5 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
.. currentmodule:: asyncio
 | 
						|
 | 
						|
.. _asyncio-sync:
 | 
						|
 | 
						|
==========================
 | 
						|
Synchronization Primitives
 | 
						|
==========================
 | 
						|
 | 
						|
**Source code:** :source:`Lib/asyncio/locks.py`
 | 
						|
 | 
						|
-----------------------------------------------
 | 
						|
 | 
						|
asyncio synchronization primitives are designed to be similar to
 | 
						|
those of the :mod:`threading` module with two important caveats:
 | 
						|
 | 
						|
* asyncio primitives are not thread-safe, therefore they should not
 | 
						|
  be used for OS thread synchronization (use :mod:`threading` for
 | 
						|
  that);
 | 
						|
 | 
						|
* methods of these synchronization primitives do not accept the *timeout*
 | 
						|
  argument; use the :func:`asyncio.wait_for` function to perform
 | 
						|
  operations with timeouts.
 | 
						|
 | 
						|
asyncio has the following basic synchronization primitives:
 | 
						|
 | 
						|
* :class:`Lock`
 | 
						|
* :class:`Event`
 | 
						|
* :class:`Condition`
 | 
						|
* :class:`Semaphore`
 | 
						|
* :class:`BoundedSemaphore`
 | 
						|
 | 
						|
 | 
						|
---------
 | 
						|
 | 
						|
 | 
						|
Lock
 | 
						|
====
 | 
						|
 | 
						|
.. class:: Lock()
 | 
						|
 | 
						|
   Implements a mutex lock for asyncio tasks.  Not thread-safe.
 | 
						|
 | 
						|
   An asyncio lock can be used to guarantee exclusive access to a
 | 
						|
   shared resource.
 | 
						|
 | 
						|
   The preferred way to use a Lock is an :keyword:`async with`
 | 
						|
   statement::
 | 
						|
 | 
						|
       lock = asyncio.Lock()
 | 
						|
 | 
						|
       # ... later
 | 
						|
       async with lock:
 | 
						|
           # access shared state
 | 
						|
 | 
						|
   which is equivalent to::
 | 
						|
 | 
						|
       lock = asyncio.Lock()
 | 
						|
 | 
						|
       # ... later
 | 
						|
       await lock.acquire()
 | 
						|
       try:
 | 
						|
           # access shared state
 | 
						|
       finally:
 | 
						|
           lock.release()
 | 
						|
 | 
						|
   .. coroutinemethod:: acquire()
 | 
						|
 | 
						|
      Acquire the lock.
 | 
						|
 | 
						|
      This method waits until the lock is *unlocked*, sets it to
 | 
						|
      *locked* and returns ``True``.
 | 
						|
 | 
						|
      When more than one coroutine is blocked in :meth:`acquire`
 | 
						|
      waiting for the lock to be unlocked, only one coroutine
 | 
						|
      eventually proceeds.
 | 
						|
 | 
						|
      Acquiring a lock is *fair*: the coroutine that proceeds will be
 | 
						|
      the first coroutine that started waiting on the lock.
 | 
						|
 | 
						|
   .. method:: release()
 | 
						|
 | 
						|
      Release the lock.
 | 
						|
 | 
						|
      When the lock is *locked*, reset it to *unlocked* and return.
 | 
						|
 | 
						|
      If the lock is *unlocked*, a :exc:`RuntimeError` is raised.
 | 
						|
 | 
						|
   .. method:: locked()
 | 
						|
 | 
						|
      Return ``True`` if the lock is *locked*.
 | 
						|
 | 
						|
 | 
						|
Event
 | 
						|
=====
 | 
						|
 | 
						|
.. class:: Event()
 | 
						|
 | 
						|
   An event object.  Not thread-safe.
 | 
						|
 | 
						|
   An asyncio event can be used to notify multiple asyncio tasks
 | 
						|
   that some event has happened.
 | 
						|
 | 
						|
   An Event object manages an internal flag that can be set to *true*
 | 
						|
   with the :meth:`~Event.set` method and reset to *false* with the
 | 
						|
   :meth:`clear` method.  The :meth:`~Event.wait` method blocks until the
 | 
						|
   flag is set to *true*.  The flag is set to *false* initially.
 | 
						|
 | 
						|
   .. _asyncio_example_sync_event:
 | 
						|
 | 
						|
   Example::
 | 
						|
 | 
						|
      async def waiter(event):
 | 
						|
          print('waiting for it ...')
 | 
						|
          await event.wait()
 | 
						|
          print('... got it!')
 | 
						|
 | 
						|
      async def main():
 | 
						|
          # Create an Event object.
 | 
						|
          event = asyncio.Event()
 | 
						|
 | 
						|
          # Spawn a Task to wait until 'event' is set.
 | 
						|
          waiter_task = asyncio.create_task(waiter(event))
 | 
						|
 | 
						|
          # Sleep for 1 second and set the event.
 | 
						|
          await asyncio.sleep(1)
 | 
						|
          event.set()
 | 
						|
 | 
						|
          # Wait until the waiter task is finished.
 | 
						|
          await waiter_task
 | 
						|
 | 
						|
      asyncio.run(main())
 | 
						|
 | 
						|
   .. coroutinemethod:: wait()
 | 
						|
 | 
						|
      Wait until the event is set.
 | 
						|
 | 
						|
      If the event is set, return ``True`` immediately.
 | 
						|
      Otherwise block until another task calls :meth:`~Event.set`.
 | 
						|
 | 
						|
   .. method:: set()
 | 
						|
 | 
						|
      Set the event.
 | 
						|
 | 
						|
      All tasks waiting for event to be set will be immediately
 | 
						|
      awakened.
 | 
						|
 | 
						|
   .. method:: clear()
 | 
						|
 | 
						|
      Clear (unset) the event.
 | 
						|
 | 
						|
      Tasks awaiting on :meth:`~Event.wait` will now block until the
 | 
						|
      :meth:`~Event.set` method is called again.
 | 
						|
 | 
						|
   .. method:: is_set()
 | 
						|
 | 
						|
      Return ``True`` if the event is set.
 | 
						|
 | 
						|
 | 
						|
Condition
 | 
						|
=========
 | 
						|
 | 
						|
.. class:: Condition(lock=None)
 | 
						|
 | 
						|
   A Condition object.  Not thread-safe.
 | 
						|
 | 
						|
   An asyncio condition primitive can be used by a task to wait for
 | 
						|
   some event to happen and then get exclusive access to a shared
 | 
						|
   resource.
 | 
						|
 | 
						|
   In essence, a Condition object combines the functionality
 | 
						|
   of an :class:`Event` and a :class:`Lock`.  It is possible to have
 | 
						|
   multiple Condition objects share one Lock, which allows coordinating
 | 
						|
   exclusive access to a shared resource between different tasks
 | 
						|
   interested in particular states of that shared resource.
 | 
						|
 | 
						|
   The optional *lock* argument must be a :class:`Lock` object or
 | 
						|
   ``None``.  In the latter case a new Lock object is created
 | 
						|
   automatically.
 | 
						|
 | 
						|
   The preferred way to use a Condition is an :keyword:`async with`
 | 
						|
   statement::
 | 
						|
 | 
						|
       cond = asyncio.Condition()
 | 
						|
 | 
						|
       # ... later
 | 
						|
       async with cond:
 | 
						|
           await cond.wait()
 | 
						|
 | 
						|
   which is equivalent to::
 | 
						|
 | 
						|
       cond = asyncio.Condition()
 | 
						|
 | 
						|
       # ... later
 | 
						|
       await cond.acquire()
 | 
						|
       try:
 | 
						|
           await cond.wait()
 | 
						|
       finally:
 | 
						|
           cond.release()
 | 
						|
 | 
						|
   .. coroutinemethod:: acquire()
 | 
						|
 | 
						|
      Acquire the underlying lock.
 | 
						|
 | 
						|
      This method waits until the underlying lock is *unlocked*,
 | 
						|
      sets it to *locked* and returns ``True``.
 | 
						|
 | 
						|
   .. method:: notify(n=1)
 | 
						|
 | 
						|
      Wake up at most *n* tasks (1 by default) waiting on this
 | 
						|
      condition.  The method is no-op if no tasks are waiting.
 | 
						|
 | 
						|
      The lock must be acquired before this method is called and
 | 
						|
      released shortly after.  If called with an *unlocked* lock
 | 
						|
      a :exc:`RuntimeError` error is raised.
 | 
						|
 | 
						|
   .. method:: locked()
 | 
						|
 | 
						|
      Return ``True`` if the underlying lock is acquired.
 | 
						|
 | 
						|
   .. method:: notify_all()
 | 
						|
 | 
						|
      Wake up all tasks waiting on this condition.
 | 
						|
 | 
						|
      This method acts like :meth:`notify`, but wakes up all waiting
 | 
						|
      tasks.
 | 
						|
 | 
						|
      The lock must be acquired before this method is called and
 | 
						|
      released shortly after.  If called with an *unlocked* lock
 | 
						|
      a :exc:`RuntimeError` error is raised.
 | 
						|
 | 
						|
   .. method:: release()
 | 
						|
 | 
						|
      Release the underlying lock.
 | 
						|
 | 
						|
      When invoked on an unlocked lock, a :exc:`RuntimeError` is
 | 
						|
      raised.
 | 
						|
 | 
						|
   .. coroutinemethod:: wait()
 | 
						|
 | 
						|
      Wait until notified.
 | 
						|
 | 
						|
      If the calling task has not acquired the lock when this method is
 | 
						|
      called, a :exc:`RuntimeError` is raised.
 | 
						|
 | 
						|
      This method releases the underlying lock, and then blocks until
 | 
						|
      it is awakened by a :meth:`notify` or :meth:`notify_all` call.
 | 
						|
      Once awakened, the Condition re-acquires its lock and this method
 | 
						|
      returns ``True``.
 | 
						|
 | 
						|
   .. coroutinemethod:: wait_for(predicate)
 | 
						|
 | 
						|
      Wait until a predicate becomes *true*.
 | 
						|
 | 
						|
      The predicate must be a callable which result will be
 | 
						|
      interpreted as a boolean value.  The final value is the
 | 
						|
      return value.
 | 
						|
 | 
						|
 | 
						|
Semaphore
 | 
						|
=========
 | 
						|
 | 
						|
.. class:: Semaphore(value=1)
 | 
						|
 | 
						|
   A Semaphore object.  Not thread-safe.
 | 
						|
 | 
						|
   A semaphore manages an internal counter which is decremented by each
 | 
						|
   :meth:`acquire` call and incremented by each :meth:`release` call.
 | 
						|
   The counter can never go below zero; when :meth:`acquire` finds
 | 
						|
   that it is zero, it blocks, waiting until some task calls
 | 
						|
   :meth:`release`.
 | 
						|
 | 
						|
   The optional *value* argument gives the initial value for the
 | 
						|
   internal counter (``1`` by default). If the given value is
 | 
						|
   less than ``0`` a :exc:`ValueError` is raised.
 | 
						|
 | 
						|
   The preferred way to use a Semaphore is an :keyword:`async with`
 | 
						|
   statement::
 | 
						|
 | 
						|
       sem = asyncio.Semaphore(10)
 | 
						|
 | 
						|
       # ... later
 | 
						|
       async with sem:
 | 
						|
           # work with shared resource
 | 
						|
 | 
						|
   which is equivalent to::
 | 
						|
 | 
						|
       sem = asyncio.Semaphore(10)
 | 
						|
 | 
						|
       # ... later
 | 
						|
       await sem.acquire()
 | 
						|
       try:
 | 
						|
           # work with shared resource
 | 
						|
       finally:
 | 
						|
           sem.release()
 | 
						|
 | 
						|
   .. coroutinemethod:: acquire()
 | 
						|
 | 
						|
      Acquire a semaphore.
 | 
						|
 | 
						|
      If the internal counter is greater than zero, decrement
 | 
						|
      it by one and return ``True`` immediately.  If it is zero, wait
 | 
						|
      until a :meth:`release` is called and return ``True``.
 | 
						|
 | 
						|
   .. method:: locked()
 | 
						|
 | 
						|
      Returns ``True`` if semaphore can not be acquired immediately.
 | 
						|
 | 
						|
   .. method:: release()
 | 
						|
 | 
						|
      Release a semaphore, incrementing the internal counter by one.
 | 
						|
      Can wake up a task waiting to acquire the semaphore.
 | 
						|
 | 
						|
      Unlike :class:`BoundedSemaphore`, :class:`Semaphore` allows
 | 
						|
      making more ``release()`` calls than ``acquire()`` calls.
 | 
						|
 | 
						|
 | 
						|
BoundedSemaphore
 | 
						|
================
 | 
						|
 | 
						|
.. class:: BoundedSemaphore(value=1)
 | 
						|
 | 
						|
   A bounded semaphore object.  Not thread-safe.
 | 
						|
 | 
						|
   Bounded Semaphore is a version of :class:`Semaphore` that raises
 | 
						|
   a :exc:`ValueError` in :meth:`~Semaphore.release` if it
 | 
						|
   increases the internal counter above the initial *value*.
 | 
						|
 | 
						|
---------
 | 
						|
 | 
						|
 | 
						|
.. versionchanged:: 3.9
 | 
						|
 | 
						|
   Acquiring a lock using ``await lock`` or ``yield from lock`` and/or
 | 
						|
   :keyword:`with` statement (``with await lock``, ``with (yield from
 | 
						|
   lock)``) was removed.  Use ``async with lock`` instead.
 |