Это уже завоевало популярность с, Отображают/уменьшают в Hadoop
$ python -m timeit -s "x=0" "x+=1"
10000000 loops, best of 3: 0.151 usec per loop
$ python -m timeit -s "x=0" "x-=-1"
10000000 loops, best of 3: 0.154 usec per loop
Похоже, у вас есть некоторая погрешность измерения
«Второй цикл надежно быстрее ...»
Вот ваше объяснение. Измените порядок вашего сценария так, чтобы сначала был рассчитан тест на вычитание, затем затем сложение, и внезапно сложение снова стало более быстрой операцией:
-= 3.05
+= 2.84
Очевидно, что-то происходит со второй половиной сценария, что делает его быстрее. Мое предположение заключается в том, что первый вызов range ()
выполняется медленнее, потому что python необходимо выделить достаточно памяти для такого длинного списка, но он может повторно использовать эту память для второй вызов range ()
:
import time
start = time.clock()
x = range(10000000)
end = time.clock()
del x
print 'first range()',end-start
start = time.clock()
x = range(10000000)
end = time.clock()
print 'second range()',end-start
Несколько запусков этого скрипта показывают, что дополнительное время, необходимое для первого range ()
, составляет почти всю разницу во времени между ' + = 'и' - = 'видно выше:
first range() 0.4
second range() 0.23
Когда вы задаете вопрос, всегда полезно сказать, какую платформу и какую версию Python вы используете. Иногда это не имеет значения. Это НЕ один из тех случаев:
time.clock ()
подходит только для Windows. Отбросьте свой собственный измерительный код и используйте -m timeit
, как показано в ответе pixelbeat.
Python 2.X range ()
создает список. Если вы используете Python 2.x, замените range
на xrange
и посмотрите, что произойдет.
Python 3.X int
- это Python2.X ] long
.
Я думаю, что «общий урок программирования» состоит в том, что действительно трудно предсказать, только глядя на исходный код, какая последовательность операторов будет самой быстрой. Программисты всех уровней часто попадают в ловушку такого рода «интуитивной» оптимизации. То, что вы думаете, что вы знаете, не обязательно может быть правдой.
Просто нет замены фактическому измерению производительности вашей программы. Престижность за это; отвечая на , почему в данном случае, несомненно, требует более глубокого изучения реализации Python.
Для языков с байтовой компиляцией, таких как Java, Python и .NET, недостаточно даже измерить производительность только одна машина. Различия между версиями виртуальных машин, реализациями трансляции собственного кода, оптимизацией для ЦП,
Самая большая проблема с Python 2.5 заключается в использовании диапазона, который будет выделять большой список для перебора. При использовании xrange, что бы ни было сделано вторым, для меня это немного быстрее. (Не уверен, что диапазон стал генератором в Python 3.)
Ваш эксперимент ошибочен. Этот эксперимент должен быть разработан таким образом, чтобы написать 2 разные программы - 1 для сложения, 1 для вычитания. Они должны быть точно такими же и выполняться в одинаковых условиях с данными, помещаемыми в файл. Затем вам нужно усреднить прогоны (по крайней мере, несколько тысяч), но вам понадобится статистик, который назовет вам подходящее число.
Если вы хотите проанализировать различные методы сложения, вычитания и цикла, снова каждый из них должна быть отдельной программой.
Экспериментальная ошибка могла возникнуть из-за перегрева процессора и других действий, происходящих с центральным процессором, поэтому я выполнял запуски по множеству шаблонов ...
Это было бы замечательно, поэтому у меня тщательно оценил ваш код, а также установил срок действия, так как я считаю его более правильным (все объявления и вызовы функций вне цикла). Обе версии я запускал пять раз.
Чтобы показать все результаты, я разместил графики в Интернете:
Итак, я прихожу к выводу, что ваш эксперимент имеет предвзятость, и это важно.
Наконец, вот мой код:
import time
addtimes = [0.] * 100
subtracttimes = [0.] * 100
range100 = range(100)
range10000000 = range(10000000)
j = 0
i = 0
x = 0
start = 0.
for j in range100:
start = time.clock()
x = 0
for i in range10000000:
x += 1
addtimes[j] = time.clock() - start
for j in range100:
start = time.clock()
x = 0
for i in range10000000:
x -= -1
subtracttimes[j] = time.clock() - start
print '+=', sum(addtimes)
print '-=', sum(subtracttimes)
Я могу воспроизвести это на моем Q6600 (Python 2.6.2); увеличение диапазона до 100000000:
('+=', 11.370000000000001)
('-=', 10.769999999999998)
Сначала несколько наблюдений:
INPLACE_ADD
vs. INPLACE_SUBTRACT
и +1 против 1. Глядя на исходный код Python, я могу сделать предположение. Это обрабатывается в ceval.c, в PyEval_EvalFrameEx
. INPLACE_ADD
имеет значительный дополнительный блок кода для обработки конкатенации строк. Этот блок не существует в INPLACE_SUBTRACT
, поскольку вы не можете вычитать строки. Это означает, что INPLACE_ADD
содержит больше собственного кода. В зависимости (в значительной степени!) От того, как код генерируется компилятором, этот дополнительный код может быть встроен в остальную часть кода INPLACE_ADD, что означает, что добавления могут сильнее ударить по кешу инструкций, чем вычитание. Это могло вызывать дополнительные попадания в кэш L2, что могло вызвать значительную разницу в производительности.
Это сильно зависит от системы, в которой вы находитесь (разные процессоры имеют разное количество кешей и архитектур кешей), используемого компилятора, включая конкретную версию и параметры компиляции (разные компиляторы по-разному решают, какие части кода на критическом пути, который определяет, как ассемблерный код объединяется в кучу) и т. д.
Кроме того, в Python 3.0.1 разница обратная (+: 15.66, -: 16.71); без сомнения, эта критическая функция сильно изменилась.
и т. д.Кроме того, в Python 3.0.1 разница обратная (+: 15.66, -: 16.71); без сомнения, эта критическая функция сильно изменилась.
и т. д.Кроме того, в Python 3.0.1 разница обратная (+: 15.66, -: 16.71); без сомнения, эта критическая функция сильно изменилась.
Обратный цикл выполняется быстрее, потому что компьютер имеет более легкий сравнение времени, если число равно 0.