Подтвердить что ты не робот

Python itertools - медленный?

Я пытаюсь использовать модуль Python itertools для ускорения тройного вложенного цикла. В приведенном ниже тестовом коде сравнивается стандартный тройной вложенный цикл с методом и выходами продукта itertools:

Вложенное время цикла = 2,35023 сек.

Время цикла Itertools = 2.67766 секунд

Я что-то пропустил?

import numpy
import itertools
import time

n = 128
a = numpy.arange(n**3).reshape((n,n,n))
b = numpy.zeros((n,n,n))
c = numpy.zeros((n,n,n))

t = time.time()
for i in range(n):
    for j in range(n):
        for k in range(n):
            b[i,j,k] = a[i,j,k]
print 'Nested loop time = %g secs' % (time.time() - t)

t = time.time()
for (i,j,k) in itertools.product(range(n), repeat=3):
    c[i,j,k] = a[i,j,k]
print 'Itertools loop time = %g secs' % (time.time() - t)
4b9b3361

Ответ 1

Кажется, что itertools.product медленнее для больших значений n:

In [24]: print _23
from itertools import product

def nested_loops(n):
    for i in range(n):
        for j in range(n):
            for k in range(n):
                pass

def itertools_product(n):
    for (i,j,k) in product(range(n), repeat=3):
        pass


In [25]: %timeit nested_loops(128)
10 loops, best of 3: 68.6 ms per loop

In [26]: %timeit itertools_product(128)
10 loops, best of 3: 162 ms per loop

In [27]: %timeit nested_loops(10)
10000 loops, best of 3: 84.5 us per loop

In [28]: %timeit itertools_product(10)
10000 loops, best of 3: 79.8 us per loop

In [30]: %timeit nested_loops(300)
1 loops, best of 3: 833 ms per loop

In [31]: %timeit itertools_product(300)
1 loops, best of 3: 2.07 s per loop

И без распаковки кортежа:

In [40]: print _39
from itertools import product

def itertools_product(n):
    for ijk in product(range(n), repeat=3):
        pass

In [41]: %timeit itertools_product(128)
10 loops, best of 3: 115 ms per loop

In [42]: %timeit itertools_product(10)
10000 loops, best of 3: 59.2 us per loop

In [43]: %timeit itertools_product(300)
1 loops, best of 3: 1.47 s per loop

Кроме того, для развлечения, понимания списков и выражений генератора:

def list_comprehension_product(n):
    range_n = range(n)
    for (i,j,k) in [ (i, j, k) for i in range_n for j in range_n for k in range_n ]:
        pass

def generator_expression_product(n):
    range_n = range(n)
    for (i,j,k) in ( (i, j, k) for i in range_n for j in range_n for k in range_n ):
        pass

In [51]: %timeit list_comprehension_product(128)
1 loops, best of 3: 583 ms per loop

In [52]: %timeit generator_expression_product(128)
1 loops, best of 3: 480 ms per loop

Эти тесты выполнялись с помощью python --version:

2.6.7 (r267:88850, Jul 31 2011, 19:30:54) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)]

Ответ 2

Кажется, что второй цикл медленнее первого, возможно, из-за распаковки кортежа. Вам не обязательно это делать, и я нахожу, что второй цикл быстрее делает это следующим образом:

for ijk in itertools.product(range(n), repeat=3):
    c[ijk] = a[ijk]

Конечно, с numpy, вы хотите вообще не перебирать элементы, а вместо этого использовать операции numpy для всего массива сразу. Таким образом, все циклы и т.д. Выполняются на C, и вы получите огромные ускорения.