diff options
-rw-r--r-- | Doc/library/asyncio-eventloop.rst | 13 | ||||
-rw-r--r-- | Doc/library/selectors.rst | 4 | ||||
-rw-r--r-- | Lib/asyncio/base_events.py | 13 | ||||
-rw-r--r-- | Lib/asyncio/proactor_events.py | 1 | ||||
-rw-r--r-- | Lib/asyncio/selector_events.py | 1 | ||||
-rw-r--r-- | Lib/selectors.py | 21 | ||||
-rw-r--r-- | Lib/test/test_asyncio/test_base_events.py | 3 | ||||
-rw-r--r-- | Lib/test/test_asyncio/test_events.py | 23 | ||||
-rw-r--r-- | Lib/test/test_selectors.py | 5 |
9 files changed, 10 insertions, 74 deletions
diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 6c3c2df..507d5e3 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -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) diff --git a/Doc/library/selectors.rst b/Doc/library/selectors.rst index 4c322bd..98377c8 100644 --- a/Doc/library/selectors.rst +++ b/Doc/library/selectors.rst @@ -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. diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index b9de8c7..db57ee8 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -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: diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py index 6b5707c..74566b2 100644 --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -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() diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index 3690145..202c14b 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -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, *, diff --git a/Lib/selectors.py b/Lib/selectors.py index 056e45c..bb2a45a 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -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() diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py index 0d90d3f..5b05684 100644 --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -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) diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index c11d20f..c2988c0 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -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: diff --git a/Lib/test/test_selectors.py b/Lib/test/test_selectors.py index 5e55eee..34edd76 100644 --- a/Lib/test/test_selectors.py +++ b/Lib/test/test_selectors.py @@ -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: |