gh-129005: Remove copies from _pyio using take_bytes (#141539)

Memory usage now matches that of _io for large files.
This commit is contained in:
Cody Maloney 2025-11-18 01:10:32 -08:00 committed by GitHub
parent 4867f717e2
commit 58f3fe0d9b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 8 additions and 9 deletions

View file

@ -546,7 +546,7 @@ def nreadahead():
res += b res += b
if res.endswith(b"\n"): if res.endswith(b"\n"):
break break
return bytes(res) return res.take_bytes()
def __iter__(self): def __iter__(self):
self._checkClosed() self._checkClosed()
@ -620,7 +620,7 @@ def read(self, size=-1):
if n < 0 or n > len(b): if n < 0 or n > len(b):
raise ValueError(f"readinto returned {n} outside buffer size {len(b)}") raise ValueError(f"readinto returned {n} outside buffer size {len(b)}")
del b[n:] del b[n:]
return bytes(b) return b.take_bytes()
def readall(self): def readall(self):
"""Read until EOF, using multiple read() call.""" """Read until EOF, using multiple read() call."""
@ -628,7 +628,7 @@ def readall(self):
while data := self.read(DEFAULT_BUFFER_SIZE): while data := self.read(DEFAULT_BUFFER_SIZE):
res += data res += data
if res: if res:
return bytes(res) return res.take_bytes()
else: else:
# b'' or None # b'' or None
return data return data
@ -1738,7 +1738,7 @@ def readall(self):
assert len(result) - bytes_read >= 1, \ assert len(result) - bytes_read >= 1, \
"os.readinto buffer size 0 will result in erroneous EOF / returns 0" "os.readinto buffer size 0 will result in erroneous EOF / returns 0"
result.resize(bytes_read) result.resize(bytes_read)
return bytes(result) return result.take_bytes()
def readinto(self, buffer): def readinto(self, buffer):
"""Same as RawIOBase.readinto().""" """Same as RawIOBase.readinto()."""

View file

@ -1277,7 +1277,8 @@ def test_flush_and_readinto(self):
def _readinto(bufio, n=-1): def _readinto(bufio, n=-1):
b = bytearray(n if n >= 0 else 9999) b = bytearray(n if n >= 0 else 9999)
n = bufio.readinto(b) n = bufio.readinto(b)
return bytes(b[:n]) b.resize(n)
return b.take_bytes()
self.check_flush_and_read(_readinto) self.check_flush_and_read(_readinto)
def test_flush_and_peek(self): def test_flush_and_peek(self):

View file

@ -56,9 +56,7 @@ class TestFileMethods(LargeFileTest):
(i.e. > 2 GiB) files. (i.e. > 2 GiB) files.
""" """
# _pyio.FileIO.readall() uses a temporary bytearray then casted to bytes, @bigmemtest(size=size, memuse=1, dry_run=False)
# so memuse=2 is needed
@bigmemtest(size=size, memuse=2, dry_run=False)
def test_large_read(self, _size): def test_large_read(self, _size):
# bpo-24658: Test that a read greater than 2GB does not fail. # bpo-24658: Test that a read greater than 2GB does not fail.
with self.open(TESTFN, "rb") as f: with self.open(TESTFN, "rb") as f:
@ -154,7 +152,7 @@ def test_seekable(self):
f.seek(pos) f.seek(pos)
self.assertTrue(f.seekable()) self.assertTrue(f.seekable())
@bigmemtest(size=size, memuse=2, dry_run=False) @bigmemtest(size=size, memuse=1, dry_run=False)
def test_seek_readall(self, _size): def test_seek_readall(self, _size):
# Seek which doesn't change position should readall successfully. # Seek which doesn't change position should readall successfully.
with self.open(TESTFN, 'rb') as f: with self.open(TESTFN, 'rb') as f: