]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Fixes issue #19929: Call os.read with 32768 within subprocess.Popen
authorGregory P. Smith <greg@krypto.org>
Sun, 8 Dec 2013 18:58:28 +0000 (10:58 -0800)
committerGregory P. Smith <greg@krypto.org>
Sun, 8 Dec 2013 18:58:28 +0000 (10:58 -0800)
communicate rather than 4096 for efficiency.  A microbenchmark shows
Linux and OS X both using ~50% less cpu time this way.

1  2 
Lib/subprocess.py
Misc/NEWS

index e7f39fef0627be2b945a19196f93781292f70cda,78e4fcfc596e2df6756a89227247a14ec09d4fd7..e79e5fd614b8c8a73bfe3faade7a92ba077291d8
@@@ -1544,68 -1544,12 +1544,68 @@@ class Popen(object)
                  if not input:
                      self.stdin.close()
  
 -            if _has_poll:
 -                stdout, stderr = self._communicate_with_poll(input, endtime,
 -                                                             orig_timeout)
 -            else:
 -                stdout, stderr = self._communicate_with_select(input, endtime,
 -                                                               orig_timeout)
 +            stdout = None
 +            stderr = None
 +
 +            # Only create this mapping if we haven't already.
 +            if not self._communication_started:
 +                self._fileobj2output = {}
 +                if self.stdout:
 +                    self._fileobj2output[self.stdout] = []
 +                if self.stderr:
 +                    self._fileobj2output[self.stderr] = []
 +
 +            if self.stdout:
 +                stdout = self._fileobj2output[self.stdout]
 +            if self.stderr:
 +                stderr = self._fileobj2output[self.stderr]
 +
 +            self._save_input(input)
 +
 +            if self._input:
 +                input_view = memoryview(self._input)
 +
 +            with _PopenSelector() as selector:
 +                if self.stdin and input:
 +                    selector.register(self.stdin, selectors.EVENT_WRITE)
 +                if self.stdout:
 +                    selector.register(self.stdout, selectors.EVENT_READ)
 +                if self.stderr:
 +                    selector.register(self.stderr, selectors.EVENT_READ)
 +
 +                while selector.get_map():
 +                    timeout = self._remaining_time(endtime)
 +                    if timeout is not None and timeout < 0:
 +                        raise TimeoutExpired(self.args, orig_timeout)
 +
 +                    ready = selector.select(timeout)
 +                    self._check_timeout(endtime, orig_timeout)
 +
 +                    # XXX Rewrite these to use non-blocking I/O on the file
 +                    # objects; they are no longer using C stdio!
 +
 +                    for key, events in ready:
 +                        if key.fileobj is self.stdin:
 +                            chunk = input_view[self._input_offset :
 +                                               self._input_offset + _PIPE_BUF]
 +                            try:
 +                                self._input_offset += os.write(key.fd, chunk)
 +                            except OSError as e:
 +                                if e.errno == errno.EPIPE:
 +                                    selector.unregister(key.fileobj)
 +                                    key.fileobj.close()
 +                                else:
 +                                    raise
 +                            else:
 +                                if self._input_offset >= len(self._input):
 +                                    selector.unregister(key.fileobj)
 +                                    key.fileobj.close()
 +                        elif key.fileobj in (self.stdout, self.stderr):
-                             data = os.read(key.fd, 4096)
++                            data = os.read(key.fd, 32768)
 +                            if not data:
 +                                selector.unregister(key.fileobj)
 +                                key.fileobj.close()
 +                            self._fileobj2output[key.fileobj].append(data)
  
              self.wait(timeout=self._remaining_time(endtime))
  
diff --cc Misc/NEWS
index 633ef5040ea315cd7cbc9f1785807c3527eba331,5eacf9c9a5900974c4e82449eecec3b73159c30b..f81db69a3eaded002167beb4b796e358aec133c9
+++ b/Misc/NEWS
@@@ -21,9 -18,10 +21,13 @@@ Core and Builtin
  Library
  -------
  
 +- Issue #19343: Expose FreeBSD-specific APIs in resource module.  Original
 +  patch by Koobs.
 +
+ - Issue #19929: Call os.read with 32768 within subprocess.Popen.communicate
+   rather than 4096 for efficiency.  A microbenchmark shows Linux and OS X
+   both using ~50% less cpu time this way.
  - Issue #19506: Use a memoryview to avoid a data copy when piping data
    to stdin within subprocess.Popen.communicate.  5-10% less cpu usage.