mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +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:`set` method and reset to *false* with the
 | |
|    :meth:`clear` method.  The :meth:`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:`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:`wait` will now block until the
 | |
|       :meth:`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.
 | 
