Недавно я начал самообучающийся python и использовал этот язык для онлайн-курса в алгоритмах. По некоторым причинам многие из моих кодов, которые я создал для этого курса, очень медленные (относительно кодов Matlab C/С++, которые я создал в прошлом), и я начинаю беспокоиться о том, что я не правильно использую python.
Вот простой код python и matlab, чтобы сравнить их скорость.
MATLAB
for i = 1:100000000
a = 1 + 1
end
Python
for i in list(range(0, 100000000)):
a=1 + 1
Код matlab занимает около 0,3 секунды, а код python занимает около 7 секунд. Это нормально? Мои коды python для сложных задач очень медленные. Например, как назначение HW, я запускаю глубину первого поиска на графике с около 900000 узлов, и это происходит навсегда. Спасибо.
Производительность не явная цель дизайна Python:
Не слишком беспокоитесь о производительности - планируйте оптимизировать позже, когда необходимо.
Это одна из причин, почему Python интегрирован с большим количеством высокопроизводительных вычислительных бэкэнд-движков, таких как numpy, OpenBLAS и даже CUDA, просто чтобы назвать некоторые из них.
Лучший способ пойти вперёд, если вы хотите повысить производительность, - это позволить высокопроизводительным библиотекам делать тяжелую работу для вас. Оптимизация циклов внутри Python (с использованием xrange вместо диапазона в Python 2.7) не даст вам очень впечатляющих результатов.
Вот немного кода, который сравнивает разные подходы:
list(range())
xrange()
i
outкод:
import timeit
import matplotlib.pyplot as mplplt
iter = 100
testcode = [
"for i in list(range(1000000)): a = 1+1",
"for i in xrange(1000000): a = 1+1",
"for _ in xrange(1000000): a = 1+1",
"import numpy; one = numpy.ones(1000000); a = one+one",
"import pycuda.gpuarray as gpuarray; import pycuda.driver as cuda; import pycuda.autoinit; import numpy;" \
"one_gpu = gpuarray.GPUArray((1000000),numpy.int16); one_gpu.fill(1); a = (one_gpu+one_gpu).get()"
]
labels = ["list(range())", "i in xrange()", "_ in xrange()", "numpy", "numpy and CUDA"]
timings = [timeit.timeit(t, number=iter) for t in testcode]
print labels, timings
label_idx = range(len(labels))
mplplt.bar(label_idx, timings)
mplplt.xticks(label_idx, labels)
mplplt.ylabel('Execution time (sec)')
mplplt.title('Timing of integer addition in python 2.7\n(smaller value is better performance)')
mplplt.show()
Результаты (график) выполнялись на Python 2.7.13 на OSX:
Причина, по которой Numpy работает быстрее, чем решение CUDA, заключается в том, что накладные расходы на использование CUDA не влияют на эффективность Python + Numpy. Для больших вычислений с плавающей запятой CUDA делает даже лучше, чем Numpy.
Обратите внимание, что решение Numpy работает в 80 раз быстрее, чем ваше оригинальное решение. Если ваши тайминги верны, это будет даже быстрее, чем Matlab...
Последняя заметка о DFS (Depth-afirst-Search): здесь - интересная статья о DFS в Python.
Попробуйте использовать xrange
вместо range
.
Разница между ними заключается в том, что **xrange**
генерирует значения по мере их использования вместо range
, который пытается сгенерировать статический список во время выполнения.
К сожалению, потрясающая гибкость и легкость питона зависит от того, что он медленный. А также для таких больших значений итерации я предлагаю использовать модуль itertools, поскольку он имеет более быстрое кэширование.
xrange - хорошее решение, однако, если вы хотите итерации по словарям и тому подобное, лучше использовать itertools, как в этом, вы можете перебирать любой объект последовательности.
range
ведет себя по-разному между Py2 и Py3. Кроме того, в данном конкретном случае нет необходимости заключатьrange
list
.