Message135552
I experimented with a bunch of different options.
All benchmarks performed with:
$ for i in 1 4 128 256 1024 2048 4069 8192; do
echo -n "buffer_size=${i} ";
./python -m timeit -s "f=open('LICENSE','rb');b=bytearray(${i})" \
"f.seek(0)" "while f.readinto(b): pass";
done
with io.DEFAULT_BUFFER_SIZE = 8192
--------------------------------------------------------------------------------
Before patch
buffer_size=1 100 loops, best of 3: 10.4 msec per loop
buffer_size=4 100 loops, best of 3: 2.67 msec per loop
buffer_size=128 10000 loops, best of 3: 102 usec per loop
buffer_size=256 10000 loops, best of 3: 54.9 usec per loop
buffer_size=1024 10000 loops, best of 3: 26.9 usec per loop
buffer_size=2048 10000 loops, best of 3: 20.3 usec per loop
buffer_size=4069 100000 loops, best of 3: 16.3 usec per loop
buffer_size=8192 100000 loops, best of 3: 11.1 usec per loop
--------------------------------------------------------------------------------
Always read into caller's buffer
buffer_size=1 100 loops, best of 3: 14 msec per loop
buffer_size=4 100 loops, best of 3: 4.02 msec per loop
buffer_size=128 10000 loops, best of 3: 114 usec per loop
buffer_size=256 10000 loops, best of 3: 63.7 usec per loop
buffer_size=1024 100000 loops, best of 3: 19.4 usec per loop
buffer_size=2048 100000 loops, best of 3: 11.2 usec per loop
* buffer_size=4069 100000 loops, best of 3: 8.12 usec per loop
* buffer_size=8192 100000 loops, best of 3: 5.79 usec per loop
--------------------------------------------------------------------------------
Read into caller's buffer if java-like bound of internal buffer size is smaller
buffer_size=1 100 loops, best of 3: 5.01 msec per loop
buffer_size=4 1000 loops, best of 3: 1.27 msec per loop
buffer_size=128 10000 loops, best of 3: 46.9 usec per loop
buffer_size=256 10000 loops, best of 3: 29.5 usec per loop
buffer_size=1024 100000 loops, best of 3: 12.9 usec per loop
buffer_size=2048 100000 loops, best of 3: 10.8 usec per loop
buffer_size=4069 100000 loops, best of 3: 9.06 usec per loop
* buffer_size=8192 100000 loops, best of 3: 5.78 usec per loop
--------------------------------------------------------------------------------
Using bound = buffer_size / 2
buffer_size=1 100 loops, best of 3: 6.04 msec per loop
buffer_size=4 1000 loops, best of 3: 1.34 msec per loop
buffer_size=128 10000 loops, best of 3: 49.4 usec per loop
buffer_size=256 10000 loops, best of 3: 29.5 usec per loop
buffer_size=1024 100000 loops, best of 3: 13.2 usec per loop
buffer_size=2048 100000 loops, best of 3: 10.7 usec per loop
* buffer_size=4069 100000 loops, best of 3: 8.66 usec per loop
buffer_size=8192 100000 loops, best of 3: 6.1 usec per loop
--------------------------------------------------------------------------------
Using bound = buffer_size / 4
buffer_size=1 100 loops, best of 3: 5.45 msec per loop
buffer_size=4 1000 loops, best of 3: 1.34 msec per loop
buffer_size=128 10000 loops, best of 3: 49.6 usec per loop
buffer_size=256 10000 loops, best of 3: 28.8 usec per loop
buffer_size=1024 100000 loops, best of 3: 13.1 usec per loop
buffer_size=2048 100000 loops, best of 3: 12.8 usec per loop
buffer_size=4069 100000 loops, best of 3: 8.42 usec per loop
buffer_size=8192 100000 loops, best of 3: 5.93 usec per loop
--------------------------------------------------------------------------------
Always use internal buffer
* buffer_size=1 100 loops, best of 3: 4.53 msec per loop
* buffer_size=4 1000 loops, best of 3: 1.14 msec per loop
* buffer_size=128 10000 loops, best of 3: 45 usec per loop
* buffer_size=256 10000 loops, best of 3: 26.9 usec per loop
* buffer_size=1024 100000 loops, best of 3: 12.9 usec per loop
* buffer_size=2048 100000 loops, best of 3: 10.2 usec per loop
buffer_size=4069 100000 loops, best of 3: 9.15 usec per loop
buffer_size=8192 100000 loops, best of 3: 8.42 usec per loop
--------------------------------------------------------------------------------
Use read() instead
$ for i in 1 4 128 256 1024 2048 4069 8192; do
echo -n "size=${i} ";
./python -m timeit -s "f=open('LICENSE','rb');" "f.seek(0)" \
"while f.read(${i}): pass";
done
* size=1 100 loops, best of 3: 2.56 msec per loop
* size=4 1000 loops, best of 3: 709 usec per loop
* size=128 10000 loops, best of 3: 29.7 usec per loop
* size=256 100000 loops, best of 3: 18.6 usec per loop
size=1024 100000 loops, best of 3: 13.3 usec per loop
size=2048 100000 loops, best of 3: 10.8 usec per loop
size=4069 100000 loops, best of 3: 10.1 usec per loop
size=8192 100000 loops, best of 3: 6.41 usec per loop
--------------------------------------------------------------------------------
Based on the above I think you are right about using the internal buffer
regardless (revision attached). You pay a price with larger buffer sizes but on
balance it seems to be a much better general purpose solution. The java-like
solution is decent as well, it is only slightly slower for small reads and optimal
for larger buffer sizes. Personally, I would opt for the performance with larger
buffer sizes but I can only speculate as to what the general user would do. We
could always note the trade-off in the docs.
Interestingly enough it seems like using read() is a better idea
if you use a smaller size (how is that right?).
I attached the afformentioned revisions. |
|
Date |
User |
Action |
Args |
2011-05-08 23:13:07 | jcon | set | recipients:
+ jcon, pitrou, benjamin.peterson, stutzbach, daniel.urban |
2011-05-08 23:13:06 | jcon | set | messageid: <1304896386.11.0.128008274277.issue9971@psf.upfronthosting.co.za> |
2011-05-08 23:13:05 | jcon | link | issue9971 messages |
2011-05-08 23:13:05 | jcon | create | |
|