Python - преодолеть импорт вовремя

Недавно я заметил следующее о модуле timeit python:

На моей машине строки:

from timeit import Timer
t = Timer(stmt='a = 2**3**4')
print("This took {:.3f}s to execute.".format(t.timeit()))

произведет:

Это заняло 0,017 с.

С другой стороны, пишем файл test.py:

#!/usr/bin/env python3

a = 2**3**4

и звонит:

from timeit import Timer
t = Timer(stmt='import test')
print("This took {:.3f}s to execute.".format(t.timeit()))

произведет:

Это заняло 0,126 с.

И мне интересно, как я могу проверить время выполнения test.py без изменения самого файла. Как я могу обойтись без импорта файла (и, следовательно, с потерей времени).


person user9115052    schedule 18.12.2017    source источник
comment
stackoverflow.com/a/24105845/650884   -  person Pavel    schedule 18.12.2017
comment
Если вы впервые вызываете import test, python будет занят созданием test.pyc, что займет немного больше времени. Последующий импорт должен быть несколько быстрее.   -  person Aaron    schedule 18.12.2017
comment
@Aaron: За исключением того, что последующий импорт вообще ничего не будет импортировать (они проходят через кучу глупостей импорта, которые в конечном итоге заканчиваются вытаскиванием кэшированного модуля из sys.modules, который вообще не запускает модуль повторно).   -  person ShadowRanger    schedule 18.12.2017


Ответы (2)


Есть одна проблема с вашими измерениями, вы не измеряете то, что вы думаете, что измеряете, когда вы пишете:

t = Timer(stmt= 'a = 2**3**4')

Вы измеряете время привязки! Смотреть:

>>> Timer(stmt='a = 10**5**4').timeit(100000)
    0.0064544077574026915
>>> Timer(stmt='a = 2**3**4').timeit(100000)
    0.006511381058487586

Тайминги почти такие же, но для вычисления 10**5**4 он несколько дольше, чем 2**3**4. 2**3**4 вычисляется только один раз, когда код компилируется, и это называется «сворачиванием констант», некоторые оптимизации, которые Python выполняет во время компиляции вашего исходного кода.

Сравните эти два результата:

>>> Timer(stmt= 'a = 2**3**4').timeit(100000) 
    0.00628656749199763
>>> Timer(stmt= 'a = x**y**z', setup='(x,y,z)=(2,3,4)').timeit(100000) 
    0.18055968312580717

Но это ускорение не дается бесплатно. Есть два момента:

  1. Время компиляции увеличивается
  2. .pyc размер файла увеличивается (поскольку это значение хранится внутри .pyc файла)

Предположим, у меня есть два файла:

#foo1.py
a = 10**7**7

#foo2.py
x,y,z =(10,7,7)
a = x**y**z

Если я скомпилирую их с python -m py_compile foo1.py foo2.py, размеры .pyc файлов на моей машине будут:

  1. foo1.cpython-36.pyc - 364 882 байта
  2. foo2.cpython-36.pyc - 150 байт
person godaygo    schedule 18.12.2017
comment
Это действительно интересно, но я не совсем понимаю, как это конкретно связано с моим оператором импорта? Я думал, когда я импортирую test.py, уже существует test.pyc, содержащий константу, поэтому код должен быть быстрее, чем его генерация на лету (как, например, в командной строке), когда на самом деле использование импорта медленнее. - person user9115052; 19.12.2017
comment
Может быть, вы хотите проверить мой следующий вопрос а также - person user9115052; 19.12.2017

Самое близкое, что вы собираетесь получить, - это использовать compile с exec. Если вы планируете работать как файл .pyc, не включайте оператор компиляции в то, что вы рассчитываете.

# time as if executing:" >python test.pyc " from terminal
#   (importing test.py will typically automatically generate the .pyc file automatically)
t = Timer(stmt='exec(code_object)', 
          setup='code_object = compile(open("test.py").read(), "test.py", "exec")')

# time as if executing:" >python test.py " from terminal
t = Timer(stmt='exec(compile(open("test.py").read(), "test.py", "exec"))')

Это должно приблизить вас к реалистичному времени для вызова скрипта из терминала. Это не устраняет накладные расходы, потому что накладные расходы на вызов скрипта реальны и будут наблюдаться в реальном мире.

Если вы используете систему на базе Linux, вы также можете просто вызвать >time test.py с терминала.

person Aaron    schedule 18.12.2017
comment
@StefanPochmann извини, глупые опечатки. не думаю о том, что делаю. См. Править - person Aaron; 19.12.2017
comment
Хорошо, теперь это работает, но ... это занимает около 0,35 секунды, в то время как путь OP занимает всего 0,15 секунды. Было ли это на самом деле быстрее для вас, когда вы его тестировали? В этот раз ты ведь тестировал? :-П - person Stefan Pochmann; 19.12.2017
comment
Я хочу рассчитать время сценария, если я заключу его все в кавычки и поставлю как stmt в timeit. >time test.py всегда выводит намного больше времени, так как запуск Python включен. Как мне решить эту проблему? Я хочу протестировать какой-нибудь код ...code..., как если бы я использовал print(Timer.timeit(stmt='code')). - person user9115052; 19.12.2017
comment
Может быть, вы хотите проверить мой следующий вопрос а также - person user9115052; 19.12.2017
comment
@StefanPochmann это не быстрее, это представитель реального мира - person Aaron; 19.12.2017