Memory pre-allocation for large lists
Jeff Epler
jepler at unpythonic.net
Wed Feb 18 20:34:47 EST 2004
On Wed, Feb 18, 2004 at 02:33:26PM +0100, Peter Otten wrote:
> Jeremy Fincher wrote:
>
> > functor% python /usr/lib/python2.3/timeit.py 'L = [None]*1000' 'for _
> > in xrange(1000): pass'
> > 1000 loops, best of 3: 248 usec per loop
> > functor% python /usr/lib/python2.3/timeit.py 'L = []' 'for _ in
> > xrange(1000): L.append(None)'
> > 1000 loops, best of 3: 1.88e+03 usec per loop
> >
> > So there's a factor of 7.5 difference in speed there. I doubt it
> > matters, but it at least lends some credibility to the idea that
> > preallocation might be useful.
>
> In the real world, (some of) the default values have to be overwritten,
> which reduces the speed advantage to a factor of 2:
>
> $ timeit.py 'L=[None]*1000' 'for i in xrange(1000): L[i] = None'
> 1000 loops, best of 3: 338 usec per loop
> $ timeit.py 'L=[]' 'for i in xrange(1000): L.append(None)'
> 1000 loops, best of 3: 660 usec per loop
But what you're measuring here is function-call overhead.
# Item assignment
$ timeit.py 'L=[None]*1000' 'for i in xrange(1000): L[i] = None'
1000 loops, best of 3: 1.58 msec per loop
# Method resolution and function call with 1 parameter
$ timeit.py 'L=[]' 'for i in xrange(1000): L.append(None)'
100 loops, best of 3: 2.99 msec per loop
# One-at-a-time insertion with no function call overhead
$ timeit.py '[None for i in xrange(1000)]'
1000 loops, best of 3: 1.9 msec per loop
# Method resolution and function call with 2 parameters
$ timeit.py 'L=[None]*1000' 'for i in xrange(1000): L.__setitem__(i, None)'
100 loops, best of 3: 4.39 msec per loop
# Method resolution and function call with 1 parameter
$ timeit.py 'L=[None]*1000' 'for i in xrange(1000): L.__getitem__(i)'
100 loops, best of 3: 3.28 msec per loop
Jeff
More information about the Python-list
mailing list