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
|
- No more registered file descriptors. It is up to the registering
|
||||||
party to unregister a file descriptor when it is closed.
|
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
|
- ``call_later(when, callback, *args)``. Arrange for
|
||||||
``callback(*args)`` to be called approximately ``when`` seconds in
|
``callback(*args)`` to be called approximately ``when`` seconds in
|
||||||
the future, once, unless canceled. As usual in Python, ``when`` may
|
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)``.)
|
``ev.call_soon_threadsafe(ev.call_later, when, callback, *args)``.)
|
||||||
|
|
||||||
The following methods for registering callbacks for file descriptors
|
The following methods for registering callbacks for file descriptors
|
||||||
are optional. The default implementation provides them but the user
|
are optional. If they are not implemented, accessing the method
|
||||||
normally doesn't use these directly -- they are used by the transport
|
(without calling it) returns AttributeError. The default
|
||||||
implementations exclusively:
|
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
|
- ``add_reader(fd, callback, *args)``. Arrange for
|
||||||
``callback(*args)`` to be called whenever file descriptor ``fd`` is
|
``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_writer(fd)``. This is to ``add_writer()`` as
|
||||||
``remove_reader()`` is to ``add_reader()``.
|
``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
|
- TBD: A method to submit a call to a PEP 3148 executor. Or a method
|
||||||
to wait for a PEP 3148 Future. Or both.
|
to wait for a PEP 3148 Future. Or both.
|
||||||
|
|
||||||
- TBD: Methods that return ``Futures``, in particular to make a
|
- TBD: Methods that return ``Futures``, in particular to make a
|
||||||
connection and to set up a listener.
|
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
|
Callback Sequencing
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
@ -218,7 +260,7 @@ in the order in which they are registered. For example::
|
||||||
|
|
||||||
guarantees that ``foo()`` is called before ``bar()``.
|
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
|
clock were to run backwards. This is also the case for
|
||||||
``call_later(0, callback, *args)``. However, if ``call_later()`` is
|
``call_later(0, callback, *args)``. However, if ``call_later()`` is
|
||||||
used with a nonzero ``when`` argument, all bets are off if the system
|
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,
|
TBD. (Only one method, ``cancel()``, and a read-only property,
|
||||||
``canceled``. Perhaps also ``callback`` and ``args`` properties.)
|
``canceled``. Perhaps also ``callback`` and ``args`` properties.)
|
||||||
|
|
||||||
|
TBD: Find a better name?
|
||||||
|
|
||||||
Futures
|
Futures
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
@ -292,16 +336,6 @@ policy.)
|
||||||
Open Issues
|
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
|
- 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
|
||||||
|
@ -310,8 +344,18 @@ Open Issues
|
||||||
name since add_done_callback() does not guarantee that the callback
|
name since add_done_callback() does not guarantee that the callback
|
||||||
will be called in the right context.)
|
will be called in the right context.)
|
||||||
|
|
||||||
- Do we need introspection APIs? E.g. asking for the read callback
|
- Returning a Future is relatively expensive, and it is quite possible
|
||||||
given a file descriptor.
|
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
|
Acknowledgments
|
||||||
|
|
Loading…
Reference in New Issue