Refactor run*() family, rename Handler->Handle, updated intros.
This commit is contained in:
parent
ca459300f3
commit
06c6f63510
145
pep-3156.txt
145
pep-3156.txt
|
@ -17,8 +17,8 @@ Python 3.3. Consider this the concrete proposal that is missing from
|
||||||
PEP 3153. The proposal includes a pluggable event loop API, transport
|
PEP 3153. The proposal includes a pluggable event loop API, transport
|
||||||
and protocol abstractions similar to those in Twisted, and a
|
and protocol abstractions similar to those in Twisted, and a
|
||||||
higher-level scheduler based on ``yield from`` (PEP 380). A reference
|
higher-level scheduler based on ``yield from`` (PEP 380). A reference
|
||||||
implementation is in the works under the code name Tulip (the Tulip
|
implementation is in the works under the code name Tulip. The Tulip
|
||||||
repo is linked from the References section at the end).
|
repo is linked from the References section at the end.
|
||||||
|
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
|
@ -26,24 +26,33 @@ Introduction
|
||||||
|
|
||||||
The event loop is the place where most interoperability occurs. It
|
The event loop is the place where most interoperability occurs. It
|
||||||
should be easy for (Python 3.3 ports of) frameworks like Twisted,
|
should be easy for (Python 3.3 ports of) frameworks like Twisted,
|
||||||
Tornado, or ZeroMQ to either adapt the default event loop
|
Tornado, or even gevents to either adapt the default event loop
|
||||||
implementation to their needs using a lightweight wrapper or proxy, or
|
implementation to their needs using a lightweight wrapper or proxy, or
|
||||||
to replace the default event loop implementation with an adaptation of
|
to replace the default event loop implementation with an adaptation of
|
||||||
their own event loop implementation. (Some frameworks, like Twisted,
|
their own event loop implementation. (Some frameworks, like Twisted,
|
||||||
have multiple event loop implementations. This should not be a
|
have multiple event loop implementations. This should not be a
|
||||||
problem since these all have the same interface.)
|
problem since these all have the same interface.)
|
||||||
|
|
||||||
It should even be possible for two different third-party frameworks to
|
In most cases it should be possible for two different third-party
|
||||||
interoperate, either by sharing the default event loop implementation
|
frameworks to interoperate, either by sharing the default event loop
|
||||||
(each using its own adapter), or by sharing the event loop
|
implementation (each using its own adapter), or by sharing the event
|
||||||
implementation of either framework. In the latter case two levels of
|
loop implementation of either framework. In the latter case two
|
||||||
adaptation would occur (from framework A's event loop to the standard
|
levels of adaptation would occur (from framework A's event loop to the
|
||||||
event loop interface, and from there to framework B's event loop).
|
standard event loop interface, and from there to framework B's event
|
||||||
Which event loop implementation is used should be under control of the
|
loop). Which event loop implementation is used should be under
|
||||||
main program (though a default policy for event loop selection is
|
control of the main program (though a default policy for event loop
|
||||||
provided).
|
selection is provided).
|
||||||
|
|
||||||
Thus, two separate APIs are defined:
|
For this interoperability to be effective, the preferred direction of
|
||||||
|
adaptation in third party frameworks is to keep the default event loop
|
||||||
|
and adapt it to the framework's API. Ideally all third party
|
||||||
|
frameworks would give up their own event loop implementation in favor
|
||||||
|
of the standard implementation. But not all frameworks may be
|
||||||
|
satisfied with the functionality provided by the standard
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
In order to support both directions of adaptation, two separate APIs
|
||||||
|
are defined:
|
||||||
|
|
||||||
- getting and setting the current event loop object
|
- getting and setting the current event loop object
|
||||||
- the interface of a conforming event loop and its minimum guarantees
|
- the interface of a conforming event loop and its minimum guarantees
|
||||||
|
@ -118,13 +127,6 @@ Details of the interfaces between transports and protocols are given
|
||||||
later.
|
later.
|
||||||
|
|
||||||
|
|
||||||
Non-goals
|
|
||||||
=========
|
|
||||||
|
|
||||||
Interoperability with systems like Stackless Python or
|
|
||||||
greenlets/gevent is not a goal of this PEP.
|
|
||||||
|
|
||||||
|
|
||||||
Specification
|
Specification
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
@ -195,35 +197,18 @@ delays are measured in seconds, and may be ints or floats. The
|
||||||
accuracy and precision of the clock are up to the implementation; the
|
accuracy and precision of the clock are up to the implementation; the
|
||||||
default implementation uses ``time.monotonic()``.
|
default implementation uses ``time.monotonic()``.
|
||||||
|
|
||||||
A note about callbacks and Handlers: any function that takes a
|
A note about callbacks and Handles: any function that takes a
|
||||||
callback and a variable number of arguments for it can also be given a
|
callback and a variable number of arguments for it can also be given a
|
||||||
Handler object instead of the callback. Then no arguments should be
|
Handle object instead of the callback. Then no arguments should be
|
||||||
given, and the Handler should represent an immediate callback (as
|
given, and the Handle should represent an immediate callback (as
|
||||||
returned from ``call_soon()``), not a delayed callback (as returned
|
returned from ``call_soon()``), not a delayed callback (as returned
|
||||||
from ``call_later()``). If the Handler is already cancelled, the
|
from ``call_later()``). If the Handle is already cancelled, the
|
||||||
call is a no-op.
|
call is a no-op.
|
||||||
|
|
||||||
A conforming event loop object has the following methods:
|
A conforming event loop object has the following methods:
|
||||||
|
|
||||||
- ``run()``. Runs the event loop until there is nothing left to do.
|
- ``run()``. Runs the event loop until ``stop()`` is called. This
|
||||||
This means, in particular:
|
cannot be called when the event loop is already running.
|
||||||
|
|
||||||
- No more calls scheduled with ``call_later()``,
|
|
||||||
``call_repeatedly()``, ``call_soon()``, or
|
|
||||||
``call_soon_threadsafe()``, except for cancelled calls.
|
|
||||||
|
|
||||||
- No more registered file descriptors. It is up to the registering
|
|
||||||
party to unregister a file descriptor when it is closed.
|
|
||||||
|
|
||||||
Note: ``run()`` blocks until the termination condition is met,
|
|
||||||
or until ``stop()`` is called.
|
|
||||||
|
|
||||||
Note: if you schedule a call with ``call_repeatedly()``, ``run()``
|
|
||||||
will not exit until you cancel it.
|
|
||||||
|
|
||||||
TBD: How many variants of this do we really need?
|
|
||||||
|
|
||||||
- ``run_forever()``. Runs the event loop until ``stop()`` is called.
|
|
||||||
|
|
||||||
- ``run_until_complete(future, timeout=None)``. Runs the event loop
|
- ``run_until_complete(future, timeout=None)``. Runs the event loop
|
||||||
until the Future is done. If a timeout is given, it waits at most
|
until the Future is done. If a timeout is given, it waits at most
|
||||||
|
@ -232,28 +217,12 @@ A conforming event loop object has the following methods:
|
||||||
done, or if ``stop()`` is called, ``TimeoutError`` is raised (but
|
done, or if ``stop()`` is called, ``TimeoutError`` is raised (but
|
||||||
the Future is not cancelled). This cannot be called when the event
|
the Future is not cancelled). This cannot be called when the event
|
||||||
loop is already running.
|
loop is already running.
|
||||||
|
|
||||||
Note: This API is most useful for tests and the like. It should not
|
|
||||||
be used as a substitute for ``yield from future`` or other ways to
|
|
||||||
wait for a Future (e.g. registering a done callback).
|
|
||||||
|
|
||||||
- ``run_once(timeout=None)``. Run the event loop for a little while.
|
|
||||||
If a timeout is given, an I/O poll made will block at most that
|
|
||||||
long; otherwise, an I/O poll is not constrained in time.
|
|
||||||
|
|
||||||
Note: Exactlly how much work this does is up to the implementation.
|
|
||||||
One constraint: if a callback immediately schedules itself using
|
|
||||||
``call_soon()``, causing an infinite loop, ``run_once()`` should
|
|
||||||
still return.
|
|
||||||
|
|
||||||
- ``stop()``. Stops the event loop as soon as it is convenient. It
|
- ``stop()``. Stops the event loop as soon as it is convenient. It
|
||||||
is fine to restart the loop with ``run()`` (or one of its variants)
|
is fine to restart the loop with ``run()`` or ``run_until_complete()``
|
||||||
subsequently.
|
subsequently; no scheduled callbacks will be lost if this happens.
|
||||||
|
|
||||||
Note: How soon exactly is up to the implementation. All immediate
|
Note: How soon the event loop stops is up to the implementation.
|
||||||
callbacks that were already scheduled to run before ``stop()`` is
|
|
||||||
called must still be run, but callbacks scheduled after it is called
|
|
||||||
(or scheduled to be run later) will not be run.
|
|
||||||
|
|
||||||
- ``close()``. Closes the event loop, releasing any resources it may
|
- ``close()``. Closes the event loop, releasing any resources it may
|
||||||
hold, such as the file descriptor used by ``epoll()`` or
|
hold, such as the file descriptor used by ``epoll()`` or
|
||||||
|
@ -263,16 +232,23 @@ A conforming event loop object has the following methods:
|
||||||
- ``call_later(delay, callback, *args)``. Arrange for
|
- ``call_later(delay, callback, *args)``. Arrange for
|
||||||
``callback(*args)`` to be called approximately ``delay`` seconds in
|
``callback(*args)`` to be called approximately ``delay`` seconds in
|
||||||
the future, once, unless cancelled. Returns
|
the future, once, unless cancelled. Returns
|
||||||
a ``Handler`` object representing the callback, whose
|
a ``Handle`` object representing the callback, whose
|
||||||
``cancel()`` method can be used to cancel the callback.
|
``cancel()`` method can be used to cancel the callback.
|
||||||
|
If ``delay`` is <= 0, this acts like ``call_soon()`` instead.
|
||||||
|
Otherwise, callbacks scheduled for exactly the same time will be
|
||||||
|
called in an undefined order.
|
||||||
|
|
||||||
- ``call_repeatedly(interval, callback, **args)``. Like ``call_later()``
|
- ``call_repeatedly(interval, callback, **args)``. Like
|
||||||
but calls the callback repeatedly, every ``interval`` seconds,
|
``call_later()`` but calls the callback repeatedly, every (approximately)
|
||||||
until the ``Handler`` returned is cancelled. The first call is in
|
``interval`` seconds, until the ``Handle`` returned is cancelled or
|
||||||
``interval`` seconds.
|
the callback raises an exception. The first call is in
|
||||||
|
approximately ``interval`` seconds. If for whatever reason the
|
||||||
|
callback happens later than scheduled, subsequent callbacks will be
|
||||||
|
delayed for (at least) the same amount. The ``interval`` must be > 0.
|
||||||
|
|
||||||
- ``call_soon(callback, *args)``. Equivalent to ``call_later(0,
|
- ``call_soon(callback, *args)``. This schedules a callback to be
|
||||||
callback, *args)``.
|
called as soon as possible. It guarantees that callbacks are called
|
||||||
|
in the order in which they were scheduled.
|
||||||
|
|
||||||
- ``call_soon_threadsafe(callback, *args)``. Like
|
- ``call_soon_threadsafe(callback, *args)``. Like
|
||||||
``call_soon(callback, *args)``, but when called from another thread
|
``call_soon(callback, *args)``, but when called from another thread
|
||||||
|
@ -286,8 +262,8 @@ A conforming event loop object has the following methods:
|
||||||
|
|
||||||
- ``add_signal_handler(sig, callback, *args). Whenever signal ``sig``
|
- ``add_signal_handler(sig, callback, *args). Whenever signal ``sig``
|
||||||
is received, arrange for ``callback(*args)`` to be called. Returns
|
is received, arrange for ``callback(*args)`` to be called. Returns
|
||||||
a ``Handler`` which can be used to cancel the signal callback.
|
a ``Handle`` which can be used to cancel the signal callback.
|
||||||
(Cancelling the handler causes ``remove_signal_handler()`` to be
|
(Cancelling the handle causes ``remove_signal_handler()`` to be
|
||||||
called the next time the signal arrives. Explicitly calling
|
called the next time the signal arrives. Explicitly calling
|
||||||
``remove_signal_handler()`` is preferred.)
|
``remove_signal_handler()`` is preferred.)
|
||||||
Specifying another callback for the same signal replaces the
|
Specifying another callback for the same signal replaces the
|
||||||
|
@ -298,13 +274,13 @@ A conforming event loop object has the following methods:
|
||||||
signale (e.g. ``SIGKILL``), ``RuntimeError`` if this particular event
|
signale (e.g. ``SIGKILL``), ``RuntimeError`` if this particular event
|
||||||
loop instance cannot handle signals (since signals are global per
|
loop instance cannot handle signals (since signals are global per
|
||||||
process, only an event loop associated with the main thread can
|
process, only an event loop associated with the main thread can
|
||||||
handle signals).
|
handle signals). (TBD: Rename to ``set_signal_handler()``?)
|
||||||
|
|
||||||
- ``remove_signal_handler(sig)``. Removes the handler for signal
|
- ``remove_signal_handler(sig)``. Removes the handler for signal
|
||||||
``sig``, if one is set. Raises the same exceptions as
|
``sig``, if one is set. Raises the same exceptions as
|
||||||
``add_signal_handler()`` (except that it may return ``False``
|
``add_signal_handler()`` (except that it may return ``False``
|
||||||
instead raising ``RuntimeError`` for uncatchable signals). Returns
|
instead raising ``RuntimeError`` for uncatchable signals). Returns
|
||||||
``True``e\ if a handler was removed successfully, ``False`` if no
|
``True`` if a handler was removed successfully, ``False`` if no
|
||||||
handler was set.
|
handler was set.
|
||||||
|
|
||||||
Some methods in the standard conforming interface return Futures:
|
Some methods in the standard conforming interface return Futures:
|
||||||
|
@ -417,25 +393,26 @@ 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
|
||||||
ready for reading. Returns a ``Handler`` object which can be
|
ready for reading. Returns a ``Handle`` object which can be
|
||||||
used to cancel the callback. Note that, unlike ``call_later()``,
|
used to cancel the callback. Note that, unlike ``call_later()``,
|
||||||
the callback may be called many times. Calling ``add_reader()``
|
the callback may be called many times. Calling ``add_reader()``
|
||||||
again for the same file descriptor implicitly cancels the previous
|
again for the same file descriptor implicitly cancels the previous
|
||||||
callback for that file descriptor. Note: cancelling the handler
|
callback for that file descriptor. Note: cancelling the handle
|
||||||
may be delayed until the handler would be called. If you plan to
|
may be delayed until the handle would be called. If you plan to
|
||||||
close ``fd``, you should use ``remove_reader(fd)`` instead.
|
close ``fd``, you should use ``remove_reader(fd)`` instead.
|
||||||
(TBD: Change this to raise an exception if a handler
|
(TBD: Change this to raise an exception if a handle
|
||||||
is already set.)
|
is already set.) (TBD: Rename to ``set_reader()``?)
|
||||||
|
|
||||||
- ``add_writer(fd, callback, *args)``. Like ``add_reader()``,
|
- ``add_writer(fd, callback, *args)``. Like ``add_reader()``,
|
||||||
but registers the callback for writing instead of for reading.
|
but registers the callback for writing instead of for reading.
|
||||||
|
(TBD: Rename to ``set_reader()``?)
|
||||||
|
|
||||||
- ``remove_reader(fd)``. Cancels the current read callback for file
|
- ``remove_reader(fd)``. Cancels the current read callback for file
|
||||||
descriptor ``fd``, if one is set. A no-op if no callback is
|
descriptor ``fd``, if one is set. A no-op if no callback is
|
||||||
currently set for the file descriptor. (The reason for providing
|
currently set for the file descriptor. (The reason for providing
|
||||||
this alternate interface is that it is often more convenient to
|
this alternate interface is that it is often more convenient to
|
||||||
remember the file descriptor than to remember the ``Handler``
|
remember the file descriptor than to remember the ``Handle``
|
||||||
object.) Returns ``True`` if a handler was removed, ``False``
|
object.) Returns ``True`` if a callback was removed, ``False``
|
||||||
if not.
|
if not.
|
||||||
|
|
||||||
- ``remove_writer(fd)``. This is to ``add_writer()`` as
|
- ``remove_writer(fd)``. This is to ``add_writer()`` as
|
||||||
|
@ -522,13 +499,13 @@ traceback. (Examples of this category include ``KeyboardInterrupt``
|
||||||
and ``SystemExit``; it is usually unwise to treat these the same as
|
and ``SystemExit``; it is usually unwise to treat these the same as
|
||||||
most other exceptions.)
|
most other exceptions.)
|
||||||
|
|
||||||
The Handler Class
|
The Handle Class
|
||||||
-----------------
|
----------------
|
||||||
|
|
||||||
The various methods for registering callbacks (e.g. ``call_later()``)
|
The various methods for registering callbacks (e.g. ``call_later()``)
|
||||||
all return an object representing the registration that can be used to
|
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
|
cancel the callback. For want of a better name this object is called
|
||||||
a ``Handler``, although the user never needs to instantiate
|
a ``Handle``, although the user never needs to instantiate
|
||||||
instances of this class. There is one public method:
|
instances of this class. There is one public method:
|
||||||
|
|
||||||
- ``cancel()``. Attempt to cancel the callback.
|
- ``cancel()``. Attempt to cancel the callback.
|
||||||
|
@ -597,7 +574,7 @@ public API is as follows, indicating the differences with PEP 3148:
|
||||||
``call_soon()``. Note that the callback (unlike all other callbacks
|
``call_soon()``. Note that the callback (unlike all other callbacks
|
||||||
defined in this PEP, and ignoring the convention from the section
|
defined in this PEP, and ignoring the convention from the section
|
||||||
"Callback Style" below) is always called with a single argument, the
|
"Callback Style" below) is always called with a single argument, the
|
||||||
Future object, and should not be a Handler object.
|
Future object, and should not be a Handle object.
|
||||||
|
|
||||||
- ``set_result(result)``. The Future must not be done (nor cancelled)
|
- ``set_result(result)``. The Future must not be done (nor cancelled)
|
||||||
already. This makes the Future done and schedules the callbacks.
|
already. This makes the Future done and schedules the callbacks.
|
||||||
|
|
Loading…
Reference in New Issue