Hi,
When doing https://github.com/tornadoweb/tornado/pull/1109 and checking https://github.com/scrapy/scrapy/pull/803 I've run a couple of benchmarks:
The problem is that BytesIO copies the data, so using it just to make interface file-like for readonly data could be quite wasteful.
I believe this is a problem in curl_httpclient, simple_httpclient and wsgi tornado modules, and by using another wrapper (or at least by falling back to cStringIO in Python 2.x) they can be made faster and more memory efficient.
It's unfortunate that BytesIO is so slow. We have designed parts of the API around the untested assumption that StringIO or BytesIO can be faster because they don't have to allocate a contiguous block of memory until getvalue(). If that's not true and it is in fact slower, we should probably make HTTPResponse.body a regular variable and make HTTPResponse.buffer the lazy property.
BytesIO uses PyMem_Realloc / memset / memcpy to copy constructor argument contents to the internal buffer; it doesn't store a reference to original data. In pure-Python version the code is
def __init__(self, initial_bytes=None):
buf = bytearray()
if initial_bytes is not None:
buf += initial_bytes
self._buffer = buf
self._pos = 0
See also: http://bugs.python.org/issue22003
It looks like this issue has been resolved
http://hg.python.org/cpython/rev/79a5fbe2c78f
io.BytesIO() now defers making a copy until it is mutated
Yes, kudos to David Wilson!
It is likely the fix will be in Python 3.5 (~ November 2015?), but until it is released the issue affects all Python 3.x versions and all Python 2.x versions. It seems the fix won't be in 3.4.x.
Support for python 3.4 and older versions has been dropped, so this issue is moot.