[Python-checkins] peps: Took care of a few TODOs in Tulip PEP.
guido.van.rossum
python-checkins at python.org
Mon Nov 25 07:43:42 CET 2013
http://hg.python.org/peps/rev/b153272def9b
changeset: 5320:b153272def9b
user: Guido van Rossum <guido at dropbox.com>
date: Sun Nov 24 22:43:36 2013 -0800
summary:
Took care of a few TODOs in Tulip PEP.
files:
pep-3156.txt | 139 ++++++++++++++++++++++++++++++++++----
1 files changed, 123 insertions(+), 16 deletions(-)
diff --git a/pep-3156.txt b/pep-3156.txt
--- a/pep-3156.txt
+++ b/pep-3156.txt
@@ -286,6 +286,25 @@
``DefaultEventLoopPolicy``. The current event loop policy object can
be retrieved by calling ``get_event_loop_policy()``.
+Passing an Event Loop Around Explicitly
+'''''''''''''''''''''''''''''''''''''''
+
+It is possible to write code that uses an event loop without relying
+on a global or per-thread default event loop. For this purpose, all
+APIs that need access to the current event loop (and aren't methods on
+an event class) take an optional keyword argument named ``loop``. If
+this argument is ``None`` or unspecified, such APIs will call
+``get_event_loop()`` to get the default event loop, but if the
+``loop`` keyword argument is set to an event loop object, they will
+use that event loop, and pass it along to any other such APIs they
+call. For example, ``Future(loop=my_loop)`` will create a Future tied
+to the event loop ``my_loop``. When the default current event is
+``None``, the ``loop`` keyword argument is effectively mandatory.
+
+Note that an explicitly passed event loop must still belong to the
+current thread; the ``loop`` keyword argument does not magically
+change the constraints on how an event loop can be used.
+
Specifying Times
----------------
@@ -967,6 +986,7 @@
nothing and return ``False``. Otherwise, this attempts to cancel
the Future and returns ``True``. If the the cancellation attempt is
successful, eventually the Future's state will change to cancelled
+ (so that ``cancelled()`` will return ``True``)
and the callbacks will be scheduled. For regular Futures,
cancellation will always succeed immediately; but for Tasks (see
below) the task may ignore or delay the cancellation attempt.
@@ -1583,6 +1603,21 @@
is exactly the same as the argument; however, if the returned
Future is cancelled, the argument Future is unaffected.
+ A use case for this function would be a coroutine that caches a
+ query result for a coroutine that handles a request in an HTTP
+ server. When the request is cancelled by the client, we could
+ (arguably) want the query-caching coroutine to continue to run, so
+ that when the client reconnects, the query result is (hopefully)
+ cached. This could be written e.g. as follows::
+
+ @asyncio.coroutine
+ def handle_request(self, request):
+ ...
+ cached_query = self.get_cache(...)
+ if cached_query is None:
+ cached_query = yield from asyncio.shield(self.fill_cache(...))
+ ...
+
Sleeping
--------
@@ -1601,8 +1636,9 @@
Cancelling a task that's not done yet throws an
``asyncio.CancelledError`` exception into the coroutine. If the
coroutine doesn't catch this (or if it re-raises it) the task will be
-marked as cancelled; but if the coroutine somehow catches and ignores
-the exception it may continue to execute.
+marked as cancelled (i.e., ``cancelled()`` will return ``True``; but
+if the coroutine somehow catches and ignores the exception it may
+continue to execute (and ``cancelled()`` will return ``False``.
Tasks are also useful for interoperating between coroutines and
callback-based frameworks like Twisted. After converting a coroutine
@@ -1645,31 +1681,98 @@
off the coroutine when ``connection_made()`` is called.
+Synchronization
+===============
+
+Locks, events, conditions and semaphores modeled after those in the
+``threading`` module are implemented and can be accessed by importing
+the ``asyncio.locks`` submodule. Queus modeled after those in the
+``queue`` module are implemented and can be accessed by importing the
+``asyncio.queues`` submodule.
+
+In general these have a close correspondence to their threaded
+counterparts, however, blocking methods (e.g. ``aqcuire()`` on locks,
+``put()`` and ``get()`` on queues) are coroutines, and timeout
+parameters are not provided (you can use ``asyncio.wait_for()`` to add
+a timeout to a blocking call, however).
+
+The docstrings in the modules provide more complete documentation.
+
+Locks
+-----
+
+The following classes are provided by ``asyncio.locks``. For all
+these except ``Event``, the ``with`` statement may be used in
+combination with ``yield from`` to acquire the lock and ensure that
+the lock is released regardless of how the ``with`` block is left, as
+follows::
+
+ with (yield from my_lock):
+ ...
+
+
+- ``Lock``: a basic mutex, with methods ``acquire()`` (a coroutine),
+ ``locked()``, and ``release()``.
+
+- ``Event``: an event variable, with methods ``wait()`` (a coroutine),
+ ``set()``, ``clear()``, and ``is_set()``.
+
+- ``Condition``: a condition variable, with methods ``acquire()``,
+ ``wait()``, ``wait_for(predicate)`` (all three coroutines),
+ ``locked()``, ``release()``, ``notify()``, and ``notify_all()``.
+
+- ``Semaphore``: a semaphore, with methods ``acquire()`` (a
+ coroutine), ``locked()``, and ``release()``. The constructor
+ argument is the initial value (default ``1``).
+
+- ``BoundedSemaphore``: a bounded semaphore; this is similar to
+ ``Semaphore`` but the initial value is also the maximum value.
+
+Queues
+------
+
+The following classes and exceptions are provided by ``asyncio.queues``.
+
+- ``Queue``: a standard queue, with methods ``get()``, ``put()`` (both
+ coroutines), ``get_nowait()``, ''put_nowait()'', ``empty()``,
+ ``full()``, ``qsize()``, and ``maxsize()``.
+
+- ``PriorityQueue``: a subclass of ``Queue`` that retrieves entries
+ in priority order (lowest first).
+
+- ``LifoQueue``: a aubclass of ``Queue`` that retrieves the most
+ recently added entries first.
+
+- ``JoinableQueue``: a subclass of ``Queue`` with ``task_done()`` and
+ ``join()`` methods (the latter a coroutine).
+
+- ``Empty``, ``Full``: exceptions raised when ``get_nowait()`` or
+ ``put_nowait()`` is called on a queue that is empty or full,
+ respectively.
+
+
TO DO
=====
-- Document cancellation in more detail.
+- Document ``StreamReader``, ``StreamWriter``, ``open_connection()``,
+ and ``start_server()``.
-- Document locks and queues.
+- Document all places that take a ``loop`` keyword argument.
-- Document StreamReader, StreamWriter and open_connection().
+- Document ``logger`` object.
-- Document passing 'loop=...' everywhere.
-
-- Document logger object.
-
-- Document SIGCHILD handling API.
-
-- Compare all APIs with the source code to be sure there aren't any
- undocumented or unimplemented features.
+- Document ``SIGCHILD`` handling API.
Wish List
=========
-- An open_server() helper. It should take a callback which is called
- for each accepted connection with a reader and writer; the callback
- may be a coroutine (then it is wrapped in a task).
+(There is agreement that these features are desirable, but no
+implementation was available when Python 3.4 beta 1 was released, and
+the feature freeze for the rest of the Python 3.4 release cycle
+prohibits adding them in this late stage. However, they will
+hopefully be added in Python 3.5, and perhaps earlier in the PyPI
+distribution.)
- Support a "start TLS" operation to upgrade a TCP socket to SSL/TLS.
@@ -1681,6 +1784,10 @@
Open Issues
===========
+(Note that these have been resolved de facto in favor of the status
+quo by the acceptance of the PEP. However, the PEP's provisional
+status allows revising these decisions for Python 3.5.)
+
- Why do ``create_connection()`` and ``create_datagram_endpoint()``
have a ``proto`` argument but not ``create_server()``? And why are
the family, flag, proto arguments for ``getaddrinfo()`` sometimes
--
Repository URL: http://hg.python.org/peps
More information about the Python-checkins
mailing list