| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
Sorry, something went wrong.
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead. |
Sorry, something went wrong.
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead. |
Sorry, something went wrong.
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead. |
Sorry, something went wrong.
|
os.read() / _os_read_impl is used for reading from most kinds of files in Python. Definitely the limited size makes sense for pipes, but disk I/O generally wants "as big a read as possible". For instance reading regular files, such as python source code, one read call with a buffer that can fit the whole file is fastest in my experimenting. For both that case and the pipe case, it would be more efficient to figure out "whats the max read size" once (with the system calls that entails potentially) and re-use that for every subsequent read call Following your chain of pieces, could this be made to be more targeted to the specific case potentially? Two thoughts
See also: gh-117151 which is aiming to increase the default size (albeit focused around write performance) |
Sorry, something went wrong.
|
I've tried shifting the check to Lib/multiprocessing/connection.py and it seems promising, yielding the same performance improvements as having the checks in the C code. The change to os_read_impl would be reverted and the following patch applied to Lib/multiprocessing/connection.py: diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py
index b7e1e13217..4797ca4df8 100644
--- a/Lib/multiprocessing/connection.py
+++ b/Lib/multiprocessing/connection.py
@@ -18,6 +18,7 @@
import time
import tempfile
import itertools
+import stat
from . import util
@@ -391,8 +392,17 @@ def _recv(self, size, read=_read):
buf = io.BytesIO()
handle = self._handle
remaining = size
+ is_pipe = False
+ page_size = 0
+ if not _winapi:
+ page_size = os.sysconf(os.sysconf_names['SC_PAGESIZE'])
+ if size > 16 * page_size:
+ mode = os.fstat(handle).st_mode
+ is_pipe = stat.S_ISFIFO(mode)
+ limit = 16 * page_size if is_pipe else remaining
while remaining > 0:
- chunk = read(handle, remaining)
+ to_read = min(limit, remaining)
+ chunk = read(handle, to_read)
n = len(chunk)
if n == 0:
if remaining == size:
|
Sorry, something went wrong.
There was a problem hiding this comment.
Looking reasonable to me overall: Unlikely to break compatibility or reduce performance, improves default behavior. A couple smaller change requests from me.
It would be nice to add a test that will fail if something breaks / results in the "read too large on pipes resulting in bad behavior" again, although I don't see a straightforward way to do that (Maybe mocking Connection._read in a new test in _test_multiprocessing and checking the size of read when know it is a pipe?)
Sorry, something went wrong.
| import time | ||
| import tempfile | ||
| import itertools | ||
| import stat |
There was a problem hiding this comment.
Personal nitpick, PEP-8 doesn't seem to specify (https://peps.python.org/pep-0008/#imports), but I like imports to be alphabetical. itertools, time, and tempfile which were already in the code just above this are also out of order (although time and tempfile only slightly). Rest are in order. Not sure if it matters for Python core developer acceptance
Sorry, something went wrong.
There was a problem hiding this comment.
Done
Sorry, something went wrong.
| is_pipe = False | ||
| page_size = 0 | ||
| if not _winapi: | ||
| page_size = os.sysconf(os.sysconf_names['SC_PAGESIZE']) |
There was a problem hiding this comment.
Rather than do the if not _winapi here, which has to be run/interpreted per _recv call, can you add the "calculate max size for a fifo" like https://github.com/python/cpython/blob/main/Lib/multiprocessing/connection.py#L370-L379 does to choose/define the standard read function? Code here will still need to do the min logic + "is this a fifo", but at least reduces overhead work a little bit further.
Sorry, something went wrong.
There was a problem hiding this comment.
I've shifted fetching the base page size and calculating the default pipe size to the existing if _winapi block above. Is this what you meant?
Sorry, something went wrong.
There was a problem hiding this comment.
Yep, looking good
Sorry, something went wrong.
| @@ -0,0 +1 @@ | |||
| Limit reading size in os.read for pipes to default pipe size in order to avoid memory overallocation | |||
There was a problem hiding this comment.
This should be updated from os.read -> multiprocessing to follow the logic location change.
Sorry, something went wrong.
There was a problem hiding this comment.
Done
Sorry, something went wrong.
|
I think as far as I can review / needs a python core dev / someone with more project familiarity to look for high level things. Some lingering thoughts I have:
|
Sorry, something went wrong.
|
Sorry, something went wrong.
|
Hi @cmaloney, I wanted to check in and see if there are any additional steps I need to take for this pull request before it can be reviewed by a core developer. Thank you! |
Sorry, something went wrong.
|
Re: Core Review, as far as I know no other steps needed. From https://devguide.python.org/getting-started/pull-request-lifecycle/#reviewing it's mainly just patience, that document suggests a month wait before pinging other locations. |
Sorry, something went wrong.
|
There's one potential further optimization, at least on Linux. fcntl F_GETPIPE_SZ on the fd if it is a pipe should return the actual size. A pipe might have been configured differently than the platform default. Regardless I don't expect that will have been the case within this multiprocessing code. Using that (and F_SETPIPE_SZ) could be a future enhancement (assuming it proves useful). |
Sorry, something went wrong.
|
Thanks for taking this on! |
Sorry, something went wrong.
This PR uses 256KiB, not 64KiB on M1 mac (16K page). |
Sorry, something went wrong.
|
The Changelog entry was added to C API category, instead of the Library category. |
Sorry, something went wrong.
|
Nice catch. I will change the category in #123559. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Issue: #121313