Issue #20505: Remove resolution and _granularity from selectors and asyncio

* Remove selectors.BaseSelector.resolution attribute
* Remove asyncio.BaseEventLoop._granularity attribute
This commit is contained in:
Victor Stinner 2014-02-07 23:34:58 +01:00
parent c489e83432
commit 85310a50a9
9 changed files with 10 additions and 74 deletions

View File

@ -118,19 +118,6 @@ Which clock is used depends on the (platform-specific) event loop
implementation; ideally it is a monotonic clock. This will generally be
a different clock than :func:`time.time`.
The granularity of the event loop depends on the resolution of the
:meth:`~BaseEventLoop.time` method and the resolution of the selector. It is
usually between 1 ms and 16 ms. For example, a granularity of 1 ms means that
in the best case, the difference between the expected delay and the real
elapsed time is between -1 ms and +1 ms: a call scheduled in 1 nanosecond may
be called in 1 ms, and a call scheduled in 100 ms may be called in 99 ms.
The granularity is the best difference in theory. In practice, it depends on
the system load and the the time taken by tasks executed by the event loop.
For example, if a task blocks the event loop for 1 second, all tasks scheduled
in this second will be delayed. The :ref:`Handle correctly blocking functions
<asyncio-handle-blocking>` section explains how to avoid such issue.
.. method:: BaseEventLoop.call_later(delay, callback, *args)

View File

@ -98,10 +98,6 @@ below:
:class:`BaseSelector` and its concrete implementations support the
:term:`context manager` protocol.
.. attribute:: resolution
Resolution of the selector in seconds.
.. method:: register(fileobj, events, data=None)
Register a file object for selection, monitoring it for I/O events.

View File

@ -96,7 +96,6 @@ class BaseEventLoop(events.AbstractEventLoop):
self._default_executor = None
self._internal_fds = 0
self._running = False
self._granularity = time.get_clock_info('monotonic').resolution
def _make_socket_transport(self, sock, protocol, waiter=None, *,
extra=None, server=None):
@ -634,21 +633,11 @@ class BaseEventLoop(events.AbstractEventLoop):
else:
logger.log(level, 'poll took %.3f seconds', t1-t0)
else:
t0 = self.time()
event_list = self._selector.select(timeout)
dt = self.time() - t0
if timeout and not event_list and dt < timeout:
print("%s.select(%.3f ms) took %.3f ms (granularity=%.3f ms, resolution=%.3f ms)"
% (self._selector.__class__.__name__,
timeout * 1e3,
dt * 1e3,
self._granularity * 1e3,
self._selector.resolution * 1e3),
file=sys.__stderr__)
self._process_events(event_list)
# Handle 'later' callbacks that are ready.
now = self.time() + self._granularity
now = self.time()
while self._scheduled:
handle = self._scheduled[0]
if handle._when > now:

View File

@ -365,7 +365,6 @@ class BaseProactorEventLoop(base_events.BaseEventLoop):
self._selector = proactor # convenient alias
self._self_reading_future = None
self._accept_futures = {} # socket file descriptor => Future
self._granularity = max(proactor.resolution, self._granularity)
proactor.set_loop(self)
self._make_self_pipe()

View File

@ -36,7 +36,6 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop):
selector = selectors.DefaultSelector()
logger.debug('Using selector: %s', selector.__class__.__name__)
self._selector = selector
self._granularity = max(selector.resolution, self._granularity)
self._make_self_pipe()
def _make_socket_transport(self, sock, protocol, waiter=None, *,

View File

@ -83,11 +83,6 @@ class BaseSelector(metaclass=ABCMeta):
performant implementation on the current platform.
"""
@abstractproperty
def resolution(self):
"""Resolution of the selector in seconds"""
return None
@abstractmethod
def register(self, fileobj, events, data=None):
"""Register a file object.
@ -289,10 +284,6 @@ class SelectSelector(_BaseSelectorImpl):
self._readers = set()
self._writers = set()
@property
def resolution(self):
return 1e-6
def register(self, fileobj, events, data=None):
key = super().register(fileobj, events, data)
if events & EVENT_READ:
@ -345,10 +336,6 @@ if hasattr(select, 'poll'):
super().__init__()
self._poll = select.poll()
@property
def resolution(self):
return 1e-3
def register(self, fileobj, events, data=None):
key = super().register(fileobj, events, data)
poll_events = 0
@ -400,10 +387,6 @@ if hasattr(select, 'epoll'):
super().__init__()
self._epoll = select.epoll()
@property
def resolution(self):
return 1e-3
def fileno(self):
return self._epoll.fileno()
@ -468,10 +451,6 @@ if hasattr(select, 'kqueue'):
super().__init__()
self._kqueue = select.kqueue()
@property
def resolution(self):
return 1e-9
def fileno(self):
return self._kqueue.fileno()

View File

@ -124,7 +124,8 @@ class BaseEventLoopTests(unittest.TestCase):
self.loop.run_forever()
dt = self.loop.time() - t0
self.assertGreaterEqual(dt, delay - self.loop._granularity, dt)
# 50 ms: maximum granularity of the event loop
self.assertGreaterEqual(dt, delay - 0.050, dt)
# tolerate a difference of +800 ms because some Python buildbots
# are really slow
self.assertLessEqual(dt, 0.9, dt)

View File

@ -1170,28 +1170,19 @@ class EventLoopTestsMixin:
orig_run_once = self.loop._run_once
self.loop._run_once_counter = 0
self.loop._run_once = _run_once
calls = []
@asyncio.coroutine
def wait():
loop = self.loop
calls.append(loop._run_once_counter)
yield from asyncio.sleep(loop._granularity * 10, loop=loop)
calls.append(loop._run_once_counter)
yield from asyncio.sleep(loop._granularity / 10, loop=loop)
calls.append(loop._run_once_counter)
yield from asyncio.sleep(1e-2, loop=loop)
yield from asyncio.sleep(1e-4, loop=loop)
self.loop.run_until_complete(wait())
calls.append(self.loop._run_once_counter)
self.assertEqual(calls, [1, 3, 5, 6])
def test_granularity(self):
granularity = self.loop._granularity
self.assertGreater(granularity, 0.0)
# Worst expected granularity: 1 ms on Linux (limited by poll/epoll
# resolution), 15.6 ms on Windows (limited by time.monotonic
# resolution)
self.assertLess(granularity, 0.050)
# The ideal number of call is 6, but on some platforms, the selector
# may sleep at little bit less than timeout depending on the resolution
# of the clock used by the kernel. Tolerate 2 useless calls on these
# platforms.
self.assertLessEqual(self.loop._run_once_counter, 8)
class SubprocessTestsMixin:

View File

@ -363,11 +363,6 @@ class BaseSelectorTestCase(unittest.TestCase):
self.assertFalse(s.select(2))
self.assertLess(time() - t, 2.5)
def test_resolution(self):
s = self.SELECTOR()
self.assertIsInstance(s.resolution, (int, float))
self.assertGreater(s.resolution, 0.0)
class ScalableSelectorMixIn: