Как правило, при измерении (и сравнении) производительности очень важно точно измерить интересующую вас часть.
Давайте предположим, что мы хотим измерить и сравнить производительность по 3 вещам ( a , b и c). Теперь давайте присвоим каждому (теоретический) показатель производительности:
Как и в тесте производительности , мы начнем с предпосылки, что чем ниже балл, тем лучше (производительность).
В этом случае вышеупомянутые баллы ( 1, 4 , 8 - также называемые абсолютные баллы ) довольно актуальны и значимы для всех.
Но давайте также посчитаем относительные баллы : один из способов - выбрать вариант, который работает хуже всего. (c) и express в процентах относительно него:
- a :
1 / 8
= 0,125 - b :
4 / 8
= 0,500 - c:
8 / 8
= 1.000
Пока все хорошо. Абсолютный и относительный баллы являются явно пропорциональными.
Но в некоторых случаях в реальном мире точно измерить какой-то конкретный элемент c сложно (практически невозможно, если принять во внимание факторы извне программы). В этих случаях элемент + некоторые накладные расходы измеряются вместе, и окончательная оценка составляет сумма (не обязательно арифметическое сложение) баллов по элементу и накладным расходам. Цель здесь состоит в том, чтобы накладные расходы были как можно меньшими, чтобы уменьшить их влияние (вес) на общий балл.
Например, давайте возьмем огромные накладные расходы (назовите это d ) со счетом:
Вышеуказанные измерения (включая накладные расходы):
- a ( a + d ): 3
- a ( b + d ): 6
- c (c + d ): 10
Все выглядит немного иначе. Теперь относительные оценки:
- a :
(1 + 2) / (8 + 2)
= 0,333 ... - b :
(4 + 2) / (8 + 2)
= 0,600 - c:
(8 + 2) / (8 + 2)
= 1.000
Как видно, a Относительная оценка почти в три раза (на самом деле это 2. (6) раз выше) предыдущего значения (без накладных расходов).
То же самое происходит в вашем случае. Расчет 2 ** 12
является накладным. Я не говорю, что измерения неверны, но они также не точны. Что точно, так это то, что если один элемент работает лучше, чем другой без дополнительных затрат, он также будет работать лучше с дополнительными издержками, но, как я уже сказал, сравнение между ними даст неверные результаты.
Я изменил ваш код и добавил Еще 3 функции, где я просто избавился от возведения в степень.
code00.py :
#!/usr/bin/env python
import sys
import timeit
import random
def f0(mode, x, y): # the most "explicit" solution, best for readability, ... but uses a str comparison
if mode == 'mode1_method_foo':
return 0 # IRL, many lines here
elif mode == 'mode2_method_bar':
return x ** 12 # IRL, many lines here too
def f1(mode, x, y): # with int comparison
if mode == 1:
return 0
elif mode == 2:
return x ** 12
def f2(mode, x, y): # with bool
if mode:
return 0
else:
return x ** 12
# The modified versions
def f3(mode, x, y): # the most "explicit" solution, best for readability, ... but uses a str comparison
if mode == 'mode1_method_foo':
return 0 # IRL, many lines here
elif mode == 'mode2_method_bar':
return 1 # IRL, many lines here too
def f4(mode, x, y): # with int comparison
if mode == 1:
return 0
elif mode == 2:
return 1
def f5(mode, x, y): # with bool
if mode:
return 0
else:
return 1
x = random.random()
y = random.random()
args = ["mode2_method_bar", 2, False]
def main(*argv):
results = {}
funcs = [
f0,
f1,
f2,
f3,
f4,
f5,
]
print("Testing functions")
for i, func in enumerate(funcs):
t = timeit.timeit(stmt="func(arg, x, y)", setup="from __main__ import {0:s} as func, x, y, args;arg=args[int(func.__name__[-1]) % 3]".format(func.__name__), number=10000000)
results.setdefault(i // 3, []).append((func.__name__, t))
print(" Done with {0:s}".format(func.__name__))
print("\n Functions absolute scores (seconds)")
for k in results:
for result in results[k]:
print(" {0:s}: {1:.6f}".format(*result))
print("\n Functions relative scores (percents - compared to the variant that took longest)")
for k, v in results.items():
print(" Batch {0:d}".format(k))
longest = max(v, key=lambda x: x[-1])[-1]
for result in v:
print(" {0:s}: {1:.6f}".format(result[0], result[1] / longest))
if __name__ == "__main__":
print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
main(*sys.argv[1:])
print("\nDone.")
Вывод :
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q061250859]> "e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe" code00.py
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] 64bit on win32
Testing functions
Done with f0
Done with f1
Done with f2
Done with f3
Done with f4
Done with f5
Functions absolute scores (seconds)
f0: 3.833778
f1: 3.591715
f2: 3.083926
f3: 1.671274
f4: 1.467826
f5: 1.118479
Functions relative scores (percents - compared to the variant that took longest)
Batch 0
f0: 1.000000
f1: 0.936861
f2: 0.804409
Batch 1
f3: 1.000000
f4: 0.878268
f5: 0.669238
Done.
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q061250859]> "e:\Work\Dev\VEnvs\py_pc032_02.07.17_test0\Scripts\python.exe" code00.py
Python 2.7.17 (v2.7.17:c2f86d86e6, Oct 19 2019, 20:49:36) [MSC v.1500 32 bit (Intel)] 32bit on win32
Testing functions
Done with f0
Done with f1
Done with f2
Done with f3
Done with f4
Done with f5
Functions absolute scores (seconds)
f0: 3.947840
f1: 3.613213
f2: 3.384385
f3: 1.898074
f4: 1.604591
f5: 1.315465
Functions relative scores (percents - compared to the variant that took longest)
Batch 0
f0: 1.000000
f1: 0.915238
f2: 0.857275
Batch 1
f3: 1.000000
f4: 0.845379
f5: 0.693053
Done.
Примечания :
- Я запустил программу с обоими Python 2 и Python 3 (и, как видно, последний имеет некоторые улучшения скорости)
- Ключевым моментом здесь является снижение относительных баллов с Пакет 0 (исходные функции) до Пакет 1 (исходные функции без 2 ** 12 - означает меньшую нагрузку)
- Результаты могут отличаться между запусками (из-за внешних факторов: например, OS планирование процесса на CPU ), так что есть идея это максимально приближено к реальности. Необходимо выполнить несколько тестов
В вашем коде есть одна большая нагрузка : тот факт, что код, который вы хотите измерить, находится в функциях. Вызов функции, передача аргументов и возвращаемого значения довольно дорогостоящий по сравнению со сравнением как таковым , и я бы поспорил, что при синхронизации только сравнений относительные (а также абсолютные) оценки будут совершенно другими.