From fe91e9ba08a8854e2149398386702828fe3c0038 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 3 Dec 2018 13:11:41 -0800 Subject: [PATCH] [3.7] bpo-35380: Enable TCP_NODELAY for proactor event loop (GH-10867) (GH-10872) * bpo-35380: Enable TCP_NODELAY for proactor event loop (GH-10867) (cherry picked from commit 3bc0ebab17bf5a2c29d2214743c82034f82e6573) Co-authored-by: Andrew Svetlov --- Lib/asyncio/base_events.py | 11 ++++++++ Lib/asyncio/proactor_events.py | 5 ++++ Lib/asyncio/selector_events.py | 13 +-------- Lib/test/test_asyncio/test_base_events.py | 28 ++++++++++++++++++- Lib/test/test_asyncio/test_selector_events.py | 26 ----------------- .../2018-12-03-14-41-11.bpo-35380.SdRF9l.rst | 1 + 6 files changed, 45 insertions(+), 39 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-12-03-14-41-11.bpo-35380.SdRF9l.rst diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index b3b07554ec1..65e0529e1d9 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -165,6 +165,17 @@ def _run_until_complete_cb(fut): futures._get_loop(fut).stop() +if hasattr(socket, 'TCP_NODELAY'): + def _set_nodelay(sock): + if (sock.family in {socket.AF_INET, socket.AF_INET6} and + sock.type == socket.SOCK_STREAM and + sock.proto == socket.IPPROTO_TCP): + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) +else: + def _set_nodelay(sock): + pass + + class _SendfileFallbackProtocol(protocols.Protocol): def __init__(self, transp): if not isinstance(transp, transports._FlowControlMixin): diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py index 66bfb0ab11e..e350e8bc0c2 100644 --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -444,6 +444,11 @@ class _ProactorSocketTransport(_ProactorReadPipeTransport, _sendfile_compatible = constants._SendfileMode.TRY_NATIVE + def __init__(self, loop, sock, protocol, waiter=None, + extra=None, server=None): + super().__init__(loop, sock, protocol, waiter, extra, server) + base_events._set_nodelay(sock) + def _set_extra(self, sock): self._extra['socket'] = sock diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index 116c08d6ff7..d2861d34332 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -39,17 +39,6 @@ def _test_selector_event(selector, fd, event): return bool(key.events & event) -if hasattr(socket, 'TCP_NODELAY'): - def _set_nodelay(sock): - if (sock.family in {socket.AF_INET, socket.AF_INET6} and - sock.type == socket.SOCK_STREAM and - sock.proto == socket.IPPROTO_TCP): - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) -else: - def _set_nodelay(sock): - pass - - class BaseSelectorEventLoop(base_events.BaseEventLoop): """Selector event loop. @@ -733,7 +722,7 @@ class _SelectorSocketTransport(_SelectorTransport): # Disable the Nagle algorithm -- small writes will be # sent without waiting for the TCP ACK. This generally # decreases the latency (in some cases significantly.) - _set_nodelay(self._sock) + base_events._set_nodelay(self._sock) self._loop.call_soon(self._protocol.connection_made, self) # only start reading when connection_made() has been called diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py index 59d321e1c69..559ed3ec527 100644 --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -272,7 +272,7 @@ class BaseEventLoopTests(test_utils.TestCase): loop.set_debug(debug) if debug: msg = ("Non-thread-safe operation invoked on an event loop other " - "than the current one") + "than the current one") with self.assertRaisesRegex(RuntimeError, msg): loop.call_soon(cb) with self.assertRaisesRegex(RuntimeError, msg): @@ -2056,5 +2056,31 @@ class BaseLoopSockSendfileTests(test_utils.TestCase): self.run_loop(self.loop.sock_sendfile(sock, self.file, -1)) +class TestSelectorUtils(test_utils.TestCase): + def check_set_nodelay(self, sock): + opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY) + self.assertFalse(opt) + + base_events._set_nodelay(sock) + + opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY) + self.assertTrue(opt) + + @unittest.skipUnless(hasattr(socket, 'TCP_NODELAY'), + 'need socket.TCP_NODELAY') + def test_set_nodelay(self): + sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM, + proto=socket.IPPROTO_TCP) + with sock: + self.check_set_nodelay(sock) + + sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM, + proto=socket.IPPROTO_TCP) + with sock: + sock.setblocking(False) + self.check_set_nodelay(sock) + + + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py index 68b6ee9abbf..e94af28bade 100644 --- a/Lib/test/test_asyncio/test_selector_events.py +++ b/Lib/test/test_asyncio/test_selector_events.py @@ -15,7 +15,6 @@ from asyncio.selector_events import BaseSelectorEventLoop from asyncio.selector_events import _SelectorTransport from asyncio.selector_events import _SelectorSocketTransport from asyncio.selector_events import _SelectorDatagramTransport -from asyncio.selector_events import _set_nodelay from test.test_asyncio import utils as test_utils @@ -1746,30 +1745,5 @@ class SelectorDatagramTransportTests(test_utils.TestCase): exc_info=(ConnectionRefusedError, MOCK_ANY, MOCK_ANY)) -class TestSelectorUtils(test_utils.TestCase): - def check_set_nodelay(self, sock): - opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY) - self.assertFalse(opt) - - _set_nodelay(sock) - - opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY) - self.assertTrue(opt) - - @unittest.skipUnless(hasattr(socket, 'TCP_NODELAY'), - 'need socket.TCP_NODELAY') - def test_set_nodelay(self): - sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM, - proto=socket.IPPROTO_TCP) - with sock: - self.check_set_nodelay(sock) - - sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM, - proto=socket.IPPROTO_TCP) - with sock: - sock.setblocking(False) - self.check_set_nodelay(sock) - - if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Library/2018-12-03-14-41-11.bpo-35380.SdRF9l.rst b/Misc/NEWS.d/next/Library/2018-12-03-14-41-11.bpo-35380.SdRF9l.rst new file mode 100644 index 00000000000..91f86e604ea --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-12-03-14-41-11.bpo-35380.SdRF9l.rst @@ -0,0 +1 @@ +Enable TCP_NODELAY on Windows for proactor asyncio event loop.