Nested loops is strangely slow, totally at a loss.
Steven D'Aprano
steve at pearwood.info
Wed Dec 10 01:44:24 EST 2014
On Wed, 10 Dec 2014 13:20:25 +0800, Shiyao Ma wrote:
> When doing nested loop, the very first iteration of the innermost loop
> ends ultimately slow.
>
> Let's the code speak.
>
> The following code is quite contrived. Actually it's derived from my
> 3d-dct script. The actual difference is way more significant than this
> example.
>
> In case of any evil of gmail, bpaste here:
> https://bpaste.net/show/edfef62edb17
>
> # this constructs a space_len x space_len x space_len 3D coordinate
> import timeit
> from itertools import product
> space_len = 580
> space = product(xrange(space_len), xrange(space_len), xrange(space_len))
space will contain 580**3 == 195112000 items, but they are lazily
generated. Once you access an item, it is gone, never to be seen again
(until you recreate the product iterator object).
> sparse_cloud = product(xrange(1), xrange(1), xrange(1))
This, on the other hand, only has a single item, (0,0,0). When you run
this:
> for i, j, k in sparse_cloud:
> ts = timeit.default_timer()
> if (i, j, k) in space: pass
> te = timeit.default_timer()
> print("A, finish a loop with ", te-ts)
> print("Done Test A")
it tests:
(0,0,0) in space
which matches the very first item of space, which takes hardly any time
at all. But having done this, you have consumed that first value.
> sparse_cloud = product(xrange(1000), xrange(1000), xrange(1000)) for i,
> j, k in sparse_cloud:
> ts = timeit.default_timer()
> if (i, j, k) in space: pass
> te = timeit.default_timer()
> print("B, finish a loop with ", te-ts)
> print("Done Test B")
Now you create a new sparse_cloud iterator, and iterate over it. The
first loop gets
i, j, k = 0, 0, 0
and then tried to check:
(0,0,0) in space
*but* that item from has already been consumed. So it now runs through
the rest of the iterator:
(0,0,0) == (0,0,1) # False
(0,0,0) == (0,0,2) # False
(0,0,0) == (0,0,3) # False
...
(0,0,0) == (0,0,579) # False
(0,0,0) == (0,1,0) # False
(0,0,0) == (0,1,1) # False
...
(0,0,0) == (579,579,579) # False
which takes a long time.
Now the next loop gets the values:
i, j, k = 0, 0, 1
and then tried to check:
(0,0,1) in space
but space is now exhausted, and it returns False immediately. And so on
for the rest of the sparse_cloud iterator.
It would be nice if product iterators behaved like xrange() objects and
could perform "in" tests without exhausting the iterator, but they don't.
That's sad.
--
Steven
More information about the Python-list
mailing list