Add optional socket calls returning a Future. Some TBD rearrangements.
This commit is contained in:
parent
bd2ff471a3
commit
36562fee3e
76
pep-3156.txt
76
pep-3156.txt
|
@ -157,6 +157,13 @@ A conforming event loop object has the following methods:
|
|||
- No more registered file descriptors. It is up to the registering
|
||||
party to unregister a file descriptor when it is closed.
|
||||
|
||||
- TBD: Do we need an API for stopping the event loop, given that we
|
||||
have the termination condition? Is the termination condition
|
||||
compatible with other frameworks?
|
||||
|
||||
- TBD: Do we need an API to run the event loop for a little while
|
||||
(e.g. a single iteration)? If so, exactly what should it do?
|
||||
|
||||
- ``call_later(when, callback, *args)``. Arrange for
|
||||
``callback(*args)`` to be called approximately ``when`` seconds in
|
||||
the future, once, unless canceled. As usual in Python, ``when`` may
|
||||
|
@ -176,9 +183,15 @@ A conforming event loop object has the following methods:
|
|||
``ev.call_soon_threadsafe(ev.call_later, when, callback, *args)``.)
|
||||
|
||||
The following methods for registering callbacks for file descriptors
|
||||
are optional. The default implementation provides them but the user
|
||||
normally doesn't use these directly -- they are used by the transport
|
||||
implementations exclusively:
|
||||
are optional. If they are not implemented, accessing the method
|
||||
(without calling it) returns AttributeError. The default
|
||||
implementation provides them but the user normally doesn't use these
|
||||
directly -- they are used by the transport implementations
|
||||
exclusively. Also, on Windows these may be present or not depending
|
||||
on whether a select-based or IOCP-based event loop is used. These
|
||||
take integer file descriptors only, not objects with a fileno()
|
||||
method. The file descriptor should represent something pollable --
|
||||
i.e. no disk files.
|
||||
|
||||
- ``add_reader(fd, callback, *args)``. Arrange for
|
||||
``callback(*args)`` to be called whenever file descriptor ``fd`` is
|
||||
|
@ -201,12 +214,41 @@ implementations exclusively:
|
|||
- ``remove_writer(fd)``. This is to ``add_writer()`` as
|
||||
``remove_reader()`` is to ``add_reader()``.
|
||||
|
||||
The following methods for doing async I/O on sockets are optional.
|
||||
They are alternative to the previous set of optional methods, intended
|
||||
for transport implementations on Windows using IOCP (if the event loop
|
||||
supports it). The socket argument has to be a non-blocking socket.
|
||||
|
||||
- ``sock_recv(sock, n)``. Receive up to ``n`` bytes from socket
|
||||
``sock``. Returns a ``Future`` whose result on success will be a
|
||||
bytes object on success.
|
||||
|
||||
- ``sock_sendall(sock, data)``. Send bytes ``data`` to the socket
|
||||
``sock``. Returns a ``Future`` whose result on success will be
|
||||
``None``. (TBD: Is it better to emulate ``sendall()`` or ``send()``
|
||||
semantics?)
|
||||
|
||||
- ``sock_connect(sock, address)``. Connect to the given address.
|
||||
Returns a ``Future`` whose result on success will be ``None``.
|
||||
|
||||
- ``sock_accept(sock)``. Accept a connection from a socket. The
|
||||
socket must be in listening mode and bound to an address. Returns a
|
||||
``Future`` whose result on success will be a tuple ``(conn, peer)``
|
||||
where ``conn`` is a connected non-blocking socket and ``peer`` is
|
||||
the peer address.
|
||||
|
||||
Other TBD:
|
||||
|
||||
- TBD: A method to submit a call to a PEP 3148 executor. Or a method
|
||||
to wait for a PEP 3148 Future. Or both.
|
||||
|
||||
- TBD: Methods that return ``Futures``, in particular to make a
|
||||
connection and to set up a listener.
|
||||
|
||||
- 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
|
||||
-------------------
|
||||
|
||||
|
@ -218,7 +260,7 @@ in the order in which they are registered. For example::
|
|||
|
||||
guarantees that ``foo()`` is called before ``bar()``.
|
||||
|
||||
If ``call_soon()`` is used, this guarantee is even true if the system
|
||||
If ``call_soon()`` is used, this guarantee is true even if the system
|
||||
clock were to run backwards. This is also the case for
|
||||
``call_later(0, callback, *args)``. However, if ``call_later()`` is
|
||||
used with a nonzero ``when`` argument, all bets are off if the system
|
||||
|
@ -242,6 +284,8 @@ The DelayedCall Class
|
|||
TBD. (Only one method, ``cancel()``, and a read-only property,
|
||||
``canceled``. Perhaps also ``callback`` and ``args`` properties.)
|
||||
|
||||
TBD: Find a better name?
|
||||
|
||||
Futures
|
||||
-------
|
||||
|
||||
|
@ -292,16 +336,6 @@ policy.)
|
|||
Open Issues
|
||||
===========
|
||||
|
||||
- What have I missed that hasn't been marked with TBD yet?
|
||||
|
||||
- A better name for ``DelayedCall`` (I really don't like adjectives. :-)
|
||||
|
||||
- Do we need an API for stopping the event loop, given that we have
|
||||
the termination condition? Is the termination condition compatible
|
||||
with other frameworks?
|
||||
|
||||
- Do we need an API to run the event loop for a little while?
|
||||
|
||||
- Should we have ``future.add_callback(callback, *args)``, using the
|
||||
convention from the section "Callback Style" above, or should we
|
||||
stick with the PEP 3148 specification of
|
||||
|
@ -310,8 +344,18 @@ Open Issues
|
|||
name since add_done_callback() does not guarantee that the callback
|
||||
will be called in the right context.)
|
||||
|
||||
- Do we need introspection APIs? E.g. asking for the read callback
|
||||
given a file descriptor.
|
||||
- Returning a Future is relatively expensive, and it is quite possible
|
||||
that some types of calls _usually_ complete immediately
|
||||
(e.g. writing small amounts of data to a socket). A trick used by
|
||||
Richard Oudkerk in the tulip project's proactor branch makes calls
|
||||
like recv() either return a regular result or _raise_ a Future. The
|
||||
caller (likely a transport) must then write code like this::
|
||||
|
||||
try:
|
||||
res = ev.sock_recv(sock, 8192)
|
||||
except Future as f:
|
||||
yield from sch.block_future(f)
|
||||
res = f.result()
|
||||
|
||||
|
||||
Acknowledgments
|
||||
|
|
Loading…
Reference in New Issue