summaryrefslogtreecommitdiffstats
path: root/Lib/asyncio/streams.py
diff options
context:
space:
mode:
authorYury Selivanov <yury@magic.io>2016-10-05 22:01:12 (GMT)
committerYury Selivanov <yury@magic.io>2016-10-05 22:01:12 (GMT)
commit3e56ff0d08a65ea1e0fe361ae22d855acc9d65bb (patch)
tree468e4957435e220f4134db1185cbe2dc15b91a3d /Lib/asyncio/streams.py
parent5b8d4f97f8bbb357d7c8b79007fdff22e2c8d1ae (diff)
downloadcpython-3e56ff0d08a65ea1e0fe361ae22d855acc9d65bb.zip
cpython-3e56ff0d08a65ea1e0fe361ae22d855acc9d65bb.tar.gz
cpython-3e56ff0d08a65ea1e0fe361ae22d855acc9d65bb.tar.bz2
Issue #28370: Speedup asyncio.StreamReader.readexactly
Patch by Коренберг Марк.
Diffstat (limited to 'Lib/asyncio/streams.py')
-rw-r--r--Lib/asyncio/streams.py36
1 files changed, 17 insertions, 19 deletions
diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py
index b4adc7d..a82cc79 100644
--- a/Lib/asyncio/streams.py
+++ b/Lib/asyncio/streams.py
@@ -448,6 +448,7 @@ class StreamReader:
assert not self._eof, '_wait_for_data after EOF'
# Waiting for data while paused will make deadlock, so prevent it.
+ # This is essential for readexactly(n) for case when n > self._limit.
if self._paused:
self._paused = False
self._transport.resume_reading()
@@ -658,25 +659,22 @@ class StreamReader:
if n == 0:
return b''
- # There used to be "optimized" code here. It created its own
- # Future and waited until self._buffer had at least the n
- # bytes, then called read(n). Unfortunately, this could pause
- # the transport if the argument was larger than the pause
- # limit (which is twice self._limit). So now we just read()
- # into a local buffer.
-
- blocks = []
- while n > 0:
- block = yield from self.read(n)
- if not block:
- partial = b''.join(blocks)
- raise IncompleteReadError(partial, len(partial) + n)
- blocks.append(block)
- n -= len(block)
-
- assert n == 0
-
- return b''.join(blocks)
+ while len(self._buffer) < n:
+ if self._eof:
+ incomplete = bytes(self._buffer)
+ self._buffer.clear()
+ raise IncompleteReadError(incomplete, n)
+
+ yield from self._wait_for_data('readexactly')
+
+ if len(self._buffer) == n:
+ data = bytes(self._buffer)
+ self._buffer.clear()
+ else:
+ data = bytes(self._buffer[:n])
+ del self._buffer[:n]
+ self._maybe_resume_transport()
+ return data
if compat.PY35:
@coroutine