-
-
Notifications
You must be signed in to change notification settings - Fork 32.7k
bpo-27456: Ensure TCP_NODELAY is set on linux #4231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,7 +41,7 @@ def _test_selector_event(selector, fd, 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 | ||
base_events._is_stream_socket(sock.type) and | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At this point, how about switching to EAFP (Easier to Ask Forgiveness than Permission)?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that's what I'm planning to do here. There appears to be no reliable and future-proof way of checking socket type on Linux, so EAFP is the best option. The "not so good" option is to do a dance like this: if sock.type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC) == SOCK_STREAM: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer to filter flags rather than always calling setsockopt() but ignore errors. For best performance, I prefer to avoid useless syscalls.
Maybe we should add an attribute to socket.socket which returns the type without SOCK_NONBLOCK and SOCK_CLOEXEC bits. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another option is to add I think that sock.type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC) is not as future-proof as sock.type & SOCK_TYPE_MASK Shouldn't BSD/Linux devs support backward-compatibility/conventions after introducing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll do some experiments/more digging and update this PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
At the cost of maintainability, for a syscall that's called once in a socket's lifetime... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. About being "future-proof": SOCK_NONBLOCK and SOCK_CLOEXEC flags are now old and well known. But I agree that it's annoying to have to care of them :-( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. >>> def f(sock):
...: try:
...: sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
...: except OSError:
...: pass
...:
>>> sock = socket.socket(socket.AF_INET)
>>> %timeit f(sock)
500 ns ± 18.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
>>> sock = socket.socket(socket.AF_UNIX)
>>> %timeit f(sock)
1.66 µs ± 6.82 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) |
||
sock.proto == socket.IPPROTO_TCP): | ||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) | ||
else: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Ensure TCP_NODELAY is set on Linux. Tests by Victor Stinner. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to add a private constant to the socket module, rather rhan using a private constant? If available, even use the Linux constant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This constant can be ~0 if SOCK_NONBLOCK is missing to prevent the if.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe, but I'd like to do that in a separate PR to the socket module first. I'd like to merge this PR as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IOW -- in my opinion this PR should be merged as is and backported to 3.6. I'll work on a new PR to expose SOCK_TYPE_MASK in socket and we'll update asyncio to use that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok with merging, backporting to 3.6 and polishing 3.7 at the end.