[Python-Dev] Re: collections module

Tim Peters tim.one at comcast.net
Sun Jan 11 20:30:11 EST 2004


[Terry Reedy]
> On enhancing list object: queue vs. deque.
>
> My general impression is that queues, while less common than stacks,
> are used enough in enough different algorithms that adding one
> implementation field to list headers so that pop(0) is an O(1)
> pointer move might be an overall win for Python.  The current O(n)
> move everything every time behavior is certainly a nuisance when
> queues are needed.

See the other msgs in this thread today -- I'm not convinced that queue-like
behavior can be supported that efficiently.

> Deques, on the other hand, seem to be more a theoretical construct.
> Algorithm books include them for completeness in describing possible
> list disciplines, but generally ignore them thereafter.  I am hard
> put to remember an algorithm that actually needs them.  They are
> certainly much rarer than queues.  So I do not think trying to make
> prepends O(1) should be considered further.

I expect that if queue-like behavior *can* be supported efficiently using an
always-contiguous vector, efficient dequeue-like behavior will fall out for
free.

> My possibly naive thought is that before reallocating, look at the
> ratio of left free to total.

I don't know what that means (neither the "left free" part nor what exactly
"total" is counting).  The devil is in the details here.

> If memmove would result in as much, or perhaps nearly as much,
> over-allocation as realloc,

memmove() leaves the total number of unused slots unchanged.  realloc can do
that too, or increase it by any amount, or decrease it by any amount.   I
just don't know what you're trying to say ... explain how it works, step by
step, in the

    q = [incoming() for i in range(1000)]
    while True:
        q.append(incoming())
        consume(q.pop(0))

example.

> then just do that.  Certainly if the ratio is small (like say .1),
> don't bother with memmove.  The exact cutoff is a tuning matter.
>
> Separate issue: for best performance, one would like to be able trade
> space for time and preallocate a large enough block so that most
> append faults result in a memmove back to the left.  Does the current
> builtin shrinkage discipline would allow this.  Or does "q=[0]*1000;
> q[:]=[]" shrink the space for q back to nearly nothing?

Python *offers* to give 992 slots back; whether the platform realloc()
accepts the offer is up to it.  In the "details are everything" department,
Python *also* creates a temp vector of length 1000, and copies all of q[:]
into it before it deletes any of q:  emptying a list is a linear-time
operation, not constant-time.  That's because it's not safe to decref
anything in a list while tearing it down (e.g., the list may be visible to a
__del__ method, which must not be allowed to see NULL pointers, or reclaimed
objects, in the list).

> (One might also want to do same for stack.  And yes, I remember:
> 'user tuning' is a 'bad idea'.  But....)




More information about the Python-Dev mailing list