Skip to content

Commit fe91e9b

Browse files
[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 3bc0eba) Co-authored-by: Andrew Svetlov <andrew.svetlov@gmail.com>
1 parent a9f435e commit fe91e9b

6 files changed

Lines changed: 45 additions & 39 deletions

File tree

Lib/asyncio/base_events.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,17 @@ def _run_until_complete_cb(fut):
165165
futures._get_loop(fut).stop()
166166

167167

168+
if hasattr(socket, 'TCP_NODELAY'):
169+
def _set_nodelay(sock):
170+
if (sock.family in {socket.AF_INET, socket.AF_INET6} and
171+
sock.type == socket.SOCK_STREAM and
172+
sock.proto == socket.IPPROTO_TCP):
173+
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
174+
else:
175+
def _set_nodelay(sock):
176+
pass
177+
178+
168179
class _SendfileFallbackProtocol(protocols.Protocol):
169180
def __init__(self, transp):
170181
if not isinstance(transp, transports._FlowControlMixin):

Lib/asyncio/proactor_events.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,11 @@ class _ProactorSocketTransport(_ProactorReadPipeTransport,
444444

445445
_sendfile_compatible = constants._SendfileMode.TRY_NATIVE
446446

447+
def __init__(self, loop, sock, protocol, waiter=None,
448+
extra=None, server=None):
449+
super().__init__(loop, sock, protocol, waiter, extra, server)
450+
base_events._set_nodelay(sock)
451+
447452
def _set_extra(self, sock):
448453
self._extra['socket'] = sock
449454

Lib/asyncio/selector_events.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,6 @@ def _test_selector_event(selector, fd, event):
3939
return bool(key.events & event)
4040

4141

42-
if hasattr(socket, 'TCP_NODELAY'):
43-
def _set_nodelay(sock):
44-
if (sock.family in {socket.AF_INET, socket.AF_INET6} and
45-
sock.type == socket.SOCK_STREAM and
46-
sock.proto == socket.IPPROTO_TCP):
47-
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
48-
else:
49-
def _set_nodelay(sock):
50-
pass
51-
52-
5342
class BaseSelectorEventLoop(base_events.BaseEventLoop):
5443
"""Selector event loop.
5544
@@ -733,7 +722,7 @@ def __init__(self, loop, sock, protocol, waiter=None,
733722
# Disable the Nagle algorithm -- small writes will be
734723
# sent without waiting for the TCP ACK. This generally
735724
# decreases the latency (in some cases significantly.)
736-
_set_nodelay(self._sock)
725+
base_events._set_nodelay(self._sock)
737726

738727
self._loop.call_soon(self._protocol.connection_made, self)
739728
# only start reading when connection_made() has been called

Lib/test/test_asyncio/test_base_events.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ def cb():
272272
loop.set_debug(debug)
273273
if debug:
274274
msg = ("Non-thread-safe operation invoked on an event loop other "
275-
"than the current one")
275+
"than the current one")
276276
with self.assertRaisesRegex(RuntimeError, msg):
277277
loop.call_soon(cb)
278278
with self.assertRaisesRegex(RuntimeError, msg):
@@ -2056,5 +2056,31 @@ def test_negative_offset(self):
20562056
self.run_loop(self.loop.sock_sendfile(sock, self.file, -1))
20572057

20582058

2059+
class TestSelectorUtils(test_utils.TestCase):
2060+
def check_set_nodelay(self, sock):
2061+
opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
2062+
self.assertFalse(opt)
2063+
2064+
base_events._set_nodelay(sock)
2065+
2066+
opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
2067+
self.assertTrue(opt)
2068+
2069+
@unittest.skipUnless(hasattr(socket, 'TCP_NODELAY'),
2070+
'need socket.TCP_NODELAY')
2071+
def test_set_nodelay(self):
2072+
sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
2073+
proto=socket.IPPROTO_TCP)
2074+
with sock:
2075+
self.check_set_nodelay(sock)
2076+
2077+
sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
2078+
proto=socket.IPPROTO_TCP)
2079+
with sock:
2080+
sock.setblocking(False)
2081+
self.check_set_nodelay(sock)
2082+
2083+
2084+
20592085
if __name__ == '__main__':
20602086
unittest.main()

Lib/test/test_asyncio/test_selector_events.py

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
from asyncio.selector_events import _SelectorTransport
1616
from asyncio.selector_events import _SelectorSocketTransport
1717
from asyncio.selector_events import _SelectorDatagramTransport
18-
from asyncio.selector_events import _set_nodelay
1918
from test.test_asyncio import utils as test_utils
2019

2120

@@ -1746,30 +1745,5 @@ def test_fatal_error_connected(self, m_exc):
17461745
exc_info=(ConnectionRefusedError, MOCK_ANY, MOCK_ANY))
17471746

17481747

1749-
class TestSelectorUtils(test_utils.TestCase):
1750-
def check_set_nodelay(self, sock):
1751-
opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
1752-
self.assertFalse(opt)
1753-
1754-
_set_nodelay(sock)
1755-
1756-
opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
1757-
self.assertTrue(opt)
1758-
1759-
@unittest.skipUnless(hasattr(socket, 'TCP_NODELAY'),
1760-
'need socket.TCP_NODELAY')
1761-
def test_set_nodelay(self):
1762-
sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
1763-
proto=socket.IPPROTO_TCP)
1764-
with sock:
1765-
self.check_set_nodelay(sock)
1766-
1767-
sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
1768-
proto=socket.IPPROTO_TCP)
1769-
with sock:
1770-
sock.setblocking(False)
1771-
self.check_set_nodelay(sock)
1772-
1773-
17741748
if __name__ == '__main__':
17751749
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Enable TCP_NODELAY on Windows for proactor asyncio event loop.

0 commit comments

Comments
 (0)