Skip to content

Commit 3bc0eba

Browse files
authored
bpo-35380: Enable TCP_NODELAY for proactor event loop (#10867)
1 parent 3bb150d commit 3bc0eba

6 files changed

Lines changed: 45 additions & 42 deletions

File tree

Lib/asyncio/base_events.py

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

170170

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

Lib/asyncio/proactor_events.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
from . import base_events
1515
from . import constants
16-
from . import events
1716
from . import futures
1817
from . import exceptions
1918
from . import protocols
@@ -445,6 +444,11 @@ class _ProactorSocketTransport(_ProactorReadPipeTransport,
445444

446445
_sendfile_compatible = constants._SendfileMode.TRY_NATIVE
447446

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+
448452
def _set_extra(self, sock):
449453
self._extra['socket'] = sock
450454

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
@@ -742,7 +731,7 @@ def __init__(self, loop, sock, protocol, waiter=None,
742731
# Disable the Nagle algorithm -- small writes will be
743732
# sent without waiting for the TCP ACK. This generally
744733
# decreases the latency (in some cases significantly.)
745-
_set_nodelay(self._sock)
734+
base_events._set_nodelay(self._sock)
746735

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

Lib/test/test_asyncio/test_base_events.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import concurrent.futures
44
import errno
5-
import logging
65
import math
76
import os
87
import socket
@@ -15,7 +14,6 @@
1514
import asyncio
1615
from asyncio import base_events
1716
from asyncio import constants
18-
from asyncio import events
1917
from test.test_asyncio import utils as test_utils
2018
from test import support
2119
from test.support.script_helper import assert_python_ok
@@ -288,7 +286,7 @@ def cb():
288286
loop.set_debug(debug)
289287
if debug:
290288
msg = ("Non-thread-safe operation invoked on an event loop other "
291-
"than the current one")
289+
"than the current one")
292290
with self.assertRaisesRegex(RuntimeError, msg):
293291
loop.call_soon(cb)
294292
with self.assertRaisesRegex(RuntimeError, msg):
@@ -2075,5 +2073,31 @@ def test_negative_offset(self):
20752073
self.run_loop(self.loop.sock_sendfile(sock, self.file, -1))
20762074

20772075

2076+
class TestSelectorUtils(test_utils.TestCase):
2077+
def check_set_nodelay(self, sock):
2078+
opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
2079+
self.assertFalse(opt)
2080+
2081+
base_events._set_nodelay(sock)
2082+
2083+
opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
2084+
self.assertTrue(opt)
2085+
2086+
@unittest.skipUnless(hasattr(socket, 'TCP_NODELAY'),
2087+
'need socket.TCP_NODELAY')
2088+
def test_set_nodelay(self):
2089+
sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
2090+
proto=socket.IPPROTO_TCP)
2091+
with sock:
2092+
self.check_set_nodelay(sock)
2093+
2094+
sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
2095+
proto=socket.IPPROTO_TCP)
2096+
with sock:
2097+
sock.setblocking(False)
2098+
self.check_set_nodelay(sock)
2099+
2100+
2101+
20782102
if __name__ == '__main__':
20792103
unittest.main()

Lib/test/test_asyncio/test_selector_events.py

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

2019

@@ -1344,30 +1343,5 @@ def test_fatal_error_connected(self, m_exc):
13441343
exc_info=(ConnectionRefusedError, MOCK_ANY, MOCK_ANY))
13451344

13461345

1347-
class TestSelectorUtils(test_utils.TestCase):
1348-
def check_set_nodelay(self, sock):
1349-
opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
1350-
self.assertFalse(opt)
1351-
1352-
_set_nodelay(sock)
1353-
1354-
opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
1355-
self.assertTrue(opt)
1356-
1357-
@unittest.skipUnless(hasattr(socket, 'TCP_NODELAY'),
1358-
'need socket.TCP_NODELAY')
1359-
def test_set_nodelay(self):
1360-
sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
1361-
proto=socket.IPPROTO_TCP)
1362-
with sock:
1363-
self.check_set_nodelay(sock)
1364-
1365-
sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
1366-
proto=socket.IPPROTO_TCP)
1367-
with sock:
1368-
sock.setblocking(False)
1369-
self.check_set_nodelay(sock)
1370-
1371-
13721346
if __name__ == '__main__':
13731347
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)