Specify Futures. Minor cleanup.

This commit is contained in:
Guido van Rossum 2012-12-13 11:58:47 -08:00
parent 56159e8da3
commit c0a378f775
1 changed files with 92 additions and 19 deletions

View File

@ -145,9 +145,12 @@ Event Loop Interface
A conforming event loop object has the following methods: A conforming event loop object has the following methods:
.. ..
Look for a better way to format method docs. PEP 12 doesn't Look for a better way to format method docs. PEP 12 doesn't seem to
seem to have one. PEP 418 uses ^^^, which makes sub-headings. have one. PEP 418 uses ^^^, which makes sub-headings. PEP 3148
Also think of adding subheadings. uses a markup which generates rather heavy layout using blockquote,
causing a blank line between each method heading and its
description. Also think of adding subheadings for different
categories of methods.
- ``run()``. Runs the event loop until there is nothing left to do. - ``run()``. Runs the event loop until there is nothing left to do.
This means, in particular: This means, in particular:
@ -183,11 +186,16 @@ A conforming event loop object has the following methods:
later time in a threadsafe manner, you can use later time in a threadsafe manner, you can use
``ev.call_soon_threadsafe(ev.call_later, when, callback, *args)``.) ``ev.call_soon_threadsafe(ev.call_later, when, callback, *args)``.)
- TBD: A way to register a callback that is already wrapped in a
``DelayedCall``. Maybe ``call_soon()`` could just check
``isinstance(callback, DelayedCall)``? It should silently skip
a canceled callback.
Some methods return Futures: Some methods return Futures:
- ``wrap_future(future)``. This takes a PEP 3148 Future (i.e., an - ``wrap_future(future)``. This takes a PEP 3148 Future (i.e., an
instance of ``concurrent.futures.Future``) and returns a Future instance of ``concurrent.futures.Future``) and returns a Future
compatible with this event loop. compatible with the event loop (i.e., a ``tulip.Future`` instance).
- ``run_in_executor(executor, function, *args)``. Arrange to call - ``run_in_executor(executor, function, *args)``. Arrange to call
``function(*args)`` in an executor (see PEP 3148). Returns a Future ``function(*args)`` in an executor (see PEP 3148). Returns a Future
@ -263,30 +271,24 @@ for transport implementations on Windows using IOCP (if the event loop
supports it). The socket argument has to be a non-blocking socket. supports it). The socket argument has to be a non-blocking socket.
- ``sock_recv(sock, n)``. Receive up to ``n`` bytes from socket - ``sock_recv(sock, n)``. Receive up to ``n`` bytes from socket
``sock``. Returns a ``Future`` whose result on success will be a ``sock``. Returns a Future whose result on success will be a
bytes object on success. bytes object on success.
- ``sock_sendall(sock, data)``. Send bytes ``data`` to the socket - ``sock_sendall(sock, data)``. Send bytes ``data`` to the socket
``sock``. Returns a ``Future`` whose result on success will be ``sock``. Returns a Future whose result on success will be
``None``. (TBD: Is it better to emulate ``sendall()`` or ``send()`` ``None``. (TBD: Is it better to emulate ``sendall()`` or ``send()``
semantics?) semantics?)
- ``sock_connect(sock, address)``. Connect to the given address. - ``sock_connect(sock, address)``. Connect to the given address.
Returns a ``Future`` whose result on success will be ``None``. Returns a Future whose result on success will be ``None``.
- ``sock_accept(sock)``. Accept a connection from a socket. The - ``sock_accept(sock)``. Accept a connection from a socket. The
socket must be in listening mode and bound to an address. Returns a socket must be in listening mode and bound to an address. Returns a
``Future`` whose result on success will be a tuple ``(conn, peer)`` Future whose result on success will be a tuple ``(conn, peer)``
where ``conn`` is a connected non-blocking socket and ``peer`` is where ``conn`` is a connected non-blocking socket and ``peer`` is
the peer address. (TBD: People tell me that this style of API is the peer address. (TBD: People tell me that this style of API is
too slow for high-volume servers. So there's also too slow for high-volume servers. So there's also
``start_serving()`` above.) ``start_serving()`` above. Then do we still need this?)
Other TBD:
- TBD: Do we need introspection APIs? E.g. asking for the read
callback given a file descriptor. Or when the next scheduled call
is. Or the list of file descriptors registered with callbacks.
Callback Sequencing Callback Sequencing
------------------- -------------------
@ -320,15 +322,76 @@ in the same event loop.
The DelayedCall Class The DelayedCall Class
--------------------- ---------------------
TBD. (Only one method, ``cancel()``, and a read-only property, The various methods for registering callbacks (e.g. ``call_later()``)
``canceled``. Perhaps also ``callback`` and ``args`` properties.) all return an object representing the registration that can be used to
cancel the callback. For want of a better name this object is called
a ``DelayedCall``, although the user never needs to instantiate
instances of this class. There is one public method:
TBD: Find a better name? - ``cancel()``. Attempt to cancel the callback.
Read-only public attributes:
- ``callback``. The callback function to be called.
- ``args``. The argument tuple with which to call the callback function.
- ``canceled``. True if ``cancel()`` has been called.
Note that some callbacks (e.g. those registered with ``call_later()``)
are meant to be called only once. Others (e.g. those registered with
``add_reader()``) are meant to be called multiple times.
TBD: An API to call the callback (encapsulating the exception handling
necessary)? Should it record how many times it has been called?
Maybe this API should just be ``__call__()``? (But it should suppress
exceptions.)
TBD: Public attribute recording the realtime value when the callback
is scheduled? (Since this is needed anyway for storing it in a heap.)
TBD: A better name for the class?
Futures Futures
------- -------
TBD. The ``tulip.Future`` class here is intentionally similar to the
``concurrent.futures.Future`` class specified by PEP 3148, but there
are slight differences. The supported public API is as follows,
indicating the differences with PEP 3148:
- ``cancel()``.
- ``cancelled()``.
- ``running()``. Note that the meaning of this method is essentially
"cannot be cancelled and isn't done yet".
- ``done()``.
- ``result()``. Difference with PEP 3148: This has no timeout
argument and does *not* wait; if the future is not yet done, it
raises an exception.
- ``exception()``. Difference with PEP 3148: This has no timeout
argument and does *not* wait; if the future is not yet done, it
raises an exception.
- ``add_done_callback(fn)``. Difference with PEP 3148: The callback
is never called immediately, and always in the context of the
caller. (Typically, a context is a thread.) You can think of this
as calling the callback through ``call_soon_threadsafe()``. Note
that the callback (unlike all other callbacks defined in this PEP)
is always called with a single argument, the Future object.
The internal methods defined in PEP 3148 are not supported.
A ``tulip.Future`` object is not acceptable to the ``wait()`` and
``as_completed()`` functions in the ``concurrent.futures`` package.
A ``tulip.Future`` object is acceptable to a yield-from expression
when used in a coroutine. See the section "Coroutines and the
Scheduler" below.
Transports Transports
---------- ----------
@ -375,6 +438,16 @@ policy.)
Open Issues Open Issues
=========== ===========
- How to spell the past tense of 'cancel'? American usage prefers
(though not absolutely dictates) 'canceled' (one ell), but outside
the US 'cancelled' (two ells) prevails. PEP 3148, whose author
currently lives in Australia, uses ``cancelled()`` as a method name
on its Future class.
- Do we need introspection APIs? E.g. asking for the read callback
given a file descriptor. Or when the next scheduled call is. Or
the list of file descriptors registered with callbacks.
- Should we have ``future.add_callback(callback, *args)``, using the - Should we have ``future.add_callback(callback, *args)``, using the
convention from the section "Callback Style" above, or should we convention from the section "Callback Style" above, or should we
stick with the PEP 3148 specification of stick with the PEP 3148 specification of