]> granicus.if.org Git - python/commitdiff
Issue #28370: Speedup asyncio.StreamReader.readexactly
authorYury Selivanov <yury@magic.io>
Wed, 5 Oct 2016 22:01:12 +0000 (18:01 -0400)
committerYury Selivanov <yury@magic.io>
Wed, 5 Oct 2016 22:01:12 +0000 (18:01 -0400)
Patch by Коренберг Марк.

Lib/asyncio/streams.py
Misc/NEWS

index b4adc7d9c68943edf30eb213576d31817243a0ae..a82cc79acaa3fb371a01d8367456be75cc997086 100644 (file)
@@ -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
index 8ea2ce23469f233e0e92aed5ae87e5d07fa3077e..354dc59ca23a6937f3711741691971118094b7ca 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -353,6 +353,9 @@ Library
 - Issue #28369: Raise RuntimeError when transport's FD is used with 
   add_reader, add_writer, etc.
 
+- Issue #28370: Speedup asyncio.StreamReader.readexactly.
+  Patch by Коренберг Марк.
+
 IDLE
 ----