Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cc66a73

Browse files
committed
Issue #22003: When initialized from a bytes object, io.BytesIO() now
defers making a copy until it is mutated, improving performance and memory use on some use cases. Patch by David Wilson.
1 parent 1151710 commit cc66a73

4 files changed

Lines changed: 205 additions & 54 deletions

File tree

Lib/test/test_memoryio.py

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io
1010
import _pyio as pyio
1111
import pickle
12+
import sys
1213

1314
class MemorySeekTestMixin:
1415

@@ -711,12 +712,57 @@ def test_setstate(self):
711712

712713
@support.cpython_only
713714
def test_sizeof(self):
714-
basesize = support.calcobjsize('P2nN2Pn')
715+
basesize = support.calcobjsize('P2nN2PnP')
715716
check = self.check_sizeof
716717
self.assertEqual(object.__sizeof__(io.BytesIO()), basesize)
717718
check(io.BytesIO(), basesize )
718-
check(io.BytesIO(b'a'), basesize + 1 + 1 )
719-
check(io.BytesIO(b'a' * 1000), basesize + 1000 + 1 )
719+
check(io.BytesIO(b'a'), basesize + 1 )
720+
check(io.BytesIO(b'a' * 1000), basesize + 1000)
721+
722+
# Various tests of copy-on-write behaviour for BytesIO.
723+
724+
def _test_cow_mutation(self, mutation):
725+
# Common code for all BytesIO copy-on-write mutation tests.
726+
imm = b' ' * 1024
727+
old_rc = sys.getrefcount(imm)
728+
memio = self.ioclass(imm)
729+
self.assertEqual(sys.getrefcount(imm), old_rc + 1)
730+
mutation(memio)
731+
self.assertEqual(sys.getrefcount(imm), old_rc)
732+
733+
@support.cpython_only
734+
def test_cow_truncate(self):
735+
# Ensure truncate causes a copy.
736+
def mutation(memio):
737+
memio.truncate(1)
738+
self._test_cow_mutation(mutation)
739+
740+
@support.cpython_only
741+
def test_cow_write(self):
742+
# Ensure write that would not cause a resize still results in a copy.
743+
def mutation(memio):
744+
memio.seek(0)
745+
memio.write(b'foo')
746+
self._test_cow_mutation(mutation)
747+
748+
@support.cpython_only
749+
def test_cow_setstate(self):
750+
# __setstate__ should cause buffer to be released.
751+
memio = self.ioclass(b'foooooo')
752+
state = memio.__getstate__()
753+
def mutation(memio):
754+
memio.__setstate__(state)
755+
self._test_cow_mutation(mutation)
756+
757+
@support.cpython_only
758+
def test_cow_mutable(self):
759+
# BytesIO should accept only Bytes for copy-on-write sharing, since
760+
# arbitrary buffer-exporting objects like bytearray() aren't guaranteed
761+
# to be immutable.
762+
ba = bytearray(1024)
763+
old_rc = sys.getrefcount(ba)
764+
memio = self.ioclass(ba)
765+
self.assertEqual(sys.getrefcount(ba), old_rc)
720766

721767
class CStringIOTest(PyStringIOTest):
722768
ioclass = io.StringIO

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,6 +1456,7 @@ Sue Williams
14561456
Carol Willing
14571457
Steven Willis
14581458
Frank Willison
1459+
David Wilson
14591460
Geoff Wilson
14601461
Greg V. Wilson
14611462
J Derek Wilson

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ Core and Builtins
113113
Library
114114
-------
115115

116+
- Issue #22003: When initialized from a bytes object, io.BytesIO() now
117+
defers making a copy until it is mutated, improving performance and
118+
memory use on some use cases. Patch by David Wilson.
119+
116120
- Issue #22018: On Windows, signal.set_wakeup_fd() now also supports sockets.
117121
A side effect is that Python depends to the WinSock library.
118122

0 commit comments

Comments
 (0)