Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Lib/asyncio/proactor_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,8 @@ def _loop_reading(self, fut=None):
# we got end-of-file so no need to reschedule a new read
return

data = self._data[:length]
# It's a new slice so make it immutable so protocols upstream don't have problems
data = bytes(memoryview(self._data)[:length])
else:
# the future will be replaced by next proactor.recv call
fut.cancel()
Expand Down
4 changes: 2 additions & 2 deletions Lib/asyncio/streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ async def read(self, n=-1):
await self._wait_for_data('read')

# This will work right even if buffer is less than n bytes
data = bytes(self._buffer[:n])
data = bytes(memoryview(self._buffer)[:n])
del self._buffer[:n]

self._maybe_resume_transport()
Expand Down Expand Up @@ -730,7 +730,7 @@ async def readexactly(self, n):
data = bytes(self._buffer)
self._buffer.clear()
else:
data = bytes(self._buffer[:n])
data = bytes(memoryview(self._buffer)[:n])
del self._buffer[:n]
self._maybe_resume_transport()
return data
Expand Down
5 changes: 4 additions & 1 deletion Lib/test/test_asyncio/test_proactor_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,10 @@ def test_loop_reading_data(self):
called_buf = bytearray(self.buffer_size)
called_buf[:len(buf)] = buf
self.loop._proactor.recv_into.assert_called_with(self.sock, called_buf)
self.protocol.data_received.assert_called_with(bytearray(buf))
self.protocol.data_received.assert_called_with(buf)
# assert_called_with maps bytearray and bytes to the same thing so check manually
# regression test for https://github.com/python/cpython/issues/99941
self.assertIsInstance(self.protocol.data_received.call_args.args[0], bytes)

@unittest.skipIf(sys.flags.optimize, "Assertions are disabled in optimized mode")
def test_loop_reading_no_data(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Made :func:`asyncio.Protocol.data_received` receive immutable object
``bytes`` instead of ``bytearrays`` with regression tests added and opted to
use ``memoryview`` to take the slices for performance on big buffers.
Performance test from ``gh-issue:21442`` done on my machine with 10
repetitions on release build with timings 0.043 (delta: 0.019) before patch
and 0.041 (delta: 0.010) after so no noticable change in performance.
Comment thread
gvanrossum marked this conversation as resolved.
Outdated