From: Gregory P. Smith Date: Sun, 8 Dec 2013 18:58:28 +0000 (-0800) Subject: Fixes issue #19929: Call os.read with 32768 within subprocess.Popen X-Git-Tag: v3.4.0b2~292 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7b83b186794cec6e5d12f43f9c1a6f20bfa4e932;p=thirdparty%2FPython%2Fcpython.git Fixes 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. --- 7b83b186794cec6e5d12f43f9c1a6f20bfa4e932 diff --cc Lib/subprocess.py index e7f39fef0627,78e4fcfc596e..e79e5fd614b8 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@@ -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 633ef5040ea3,5eacf9c9a590..f81db69a3ead --- a/Misc/NEWS +++ 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.