changeset: 89027:d853955491a2 user: Victor Stinner date: Fri Feb 07 23:34:58 2014 +0100 files: Doc/library/asyncio-eventloop.rst Doc/library/selectors.rst Lib/asyncio/base_events.py Lib/asyncio/proactor_events.py Lib/asyncio/selector_events.py Lib/selectors.py Lib/test/test_asyncio/test_base_events.py Lib/test/test_asyncio/test_events.py Lib/test/test_selectors.py description: Issue #20505: Remove resolution and _granularity from selectors and asyncio * Remove selectors.BaseSelector.resolution attribute * Remove asyncio.BaseEventLoop._granularity attribute diff -r e0a90b1c4cdf -r d853955491a2 Doc/library/asyncio-eventloop.rst --- a/Doc/library/asyncio-eventloop.rst Fri Feb 07 15:04:26 2014 -0500 +++ b/Doc/library/asyncio-eventloop.rst Fri Feb 07 23:34:58 2014 +0100 @@ -118,19 +118,6 @@ 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 -` section explains how to avoid such issue. - .. method:: BaseEventLoop.call_later(delay, callback, *args) diff -r e0a90b1c4cdf -r d853955491a2 Doc/library/selectors.rst --- a/Doc/library/selectors.rst Fri Feb 07 15:04:26 2014 -0500 +++ b/Doc/library/selectors.rst Fri Feb 07 23:34:58 2014 +0100 @@ -98,10 +98,6 @@ :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. diff -r e0a90b1c4cdf -r d853955491a2 Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py Fri Feb 07 15:04:26 2014 -0500 +++ b/Lib/asyncio/base_events.py Fri Feb 07 23:34:58 2014 +0100 @@ -96,7 +96,6 @@ 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 @@ 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: diff -r e0a90b1c4cdf -r d853955491a2 Lib/asyncio/proactor_events.py --- a/Lib/asyncio/proactor_events.py Fri Feb 07 15:04:26 2014 -0500 +++ b/Lib/asyncio/proactor_events.py Fri Feb 07 23:34:58 2014 +0100 @@ -365,7 +365,6 @@ 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() diff -r e0a90b1c4cdf -r d853955491a2 Lib/asyncio/selector_events.py --- a/Lib/asyncio/selector_events.py Fri Feb 07 15:04:26 2014 -0500 +++ b/Lib/asyncio/selector_events.py Fri Feb 07 23:34:58 2014 +0100 @@ -36,7 +36,6 @@ 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, *, diff -r e0a90b1c4cdf -r d853955491a2 Lib/selectors.py --- a/Lib/selectors.py Fri Feb 07 15:04:26 2014 -0500 +++ b/Lib/selectors.py Fri Feb 07 23:34:58 2014 +0100 @@ -83,11 +83,6 @@ 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 @@ 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 @@ 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 @@ super().__init__() self._epoll = select.epoll() - @property - def resolution(self): - return 1e-3 - def fileno(self): return self._epoll.fileno() @@ -468,10 +451,6 @@ super().__init__() self._kqueue = select.kqueue() - @property - def resolution(self): - return 1e-9 - def fileno(self): return self._kqueue.fileno() diff -r e0a90b1c4cdf -r d853955491a2 Lib/test/test_asyncio/test_base_events.py --- a/Lib/test/test_asyncio/test_base_events.py Fri Feb 07 15:04:26 2014 -0500 +++ b/Lib/test/test_asyncio/test_base_events.py Fri Feb 07 23:34:58 2014 +0100 @@ -124,7 +124,8 @@ 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) diff -r e0a90b1c4cdf -r d853955491a2 Lib/test/test_asyncio/test_events.py --- a/Lib/test/test_asyncio/test_events.py Fri Feb 07 15:04:26 2014 -0500 +++ b/Lib/test/test_asyncio/test_events.py Fri Feb 07 23:34:58 2014 +0100 @@ -1170,28 +1170,19 @@ 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: diff -r e0a90b1c4cdf -r d853955491a2 Lib/test/test_selectors.py --- a/Lib/test/test_selectors.py Fri Feb 07 15:04:26 2014 -0500 +++ b/Lib/test/test_selectors.py Fri Feb 07 23:34:58 2014 +0100 @@ -363,11 +363,6 @@ 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: