Как я могу рассчитать сегмент кода для тестирования производительности с помощью Pythons timeit? - PullRequest
129 голосов
/ 19 мая 2010

У меня есть скрипт на Python, который работает так же, как и должен, но мне нужно написать время выполнения. Я гуглил, что мне следует использовать timeit, но я не могу заставить его работать.

Мой скрипт на Python выглядит так:

import sys
import getopt
import timeit
import random
import os
import re
import ibm_db
import time
from string import maketrans
myfile = open("results_update.txt", "a")

for r in range(100):
    rannumber = random.randint(0, 100)

    update = "update TABLE set val = %i where MyCount >= '2010' and MyCount < '2012' and number = '250'" % rannumber
    #print rannumber

    conn = ibm_db.pconnect("dsn=myDB","usrname","secretPWD")

for r in range(5):
    print "Run %s\n" % r        
    ibm_db.execute(query_stmt)
 query_stmt = ibm_db.prepare(conn, update)

myfile.close()
ibm_db.close(conn)

Мне нужно время, необходимое для выполнения запроса и записи его в файл results_update.txt. Цель - проверить оператор обновления для моей базы данных с различными индексами и механизмами настройки.

Ответы [ 6 ]

220 голосов
/ 19 мая 2010

Вы можете использовать time.time() или time.clock() до и после того блока, который хотите установить по времени.

import time

t0 = time.time()
code_block
t1 = time.time()

total = t1-t0

Этот метод не так точен, как timeit (он не усредняет несколько прогонов), но он прост.

time.time() (в Windows и Linux) и time.clock() (в Linux) недостаточно точны для быстрых функций (итоговое значение = 0). В этом случае или если вы хотите усреднить время, затраченное на несколько запусков, вы должны вручную вызвать функцию несколько раз (как я думаю, вы уже делаете в своем примере код, а timeit выполняет это автоматически, когда вы устанавливаете число аргумент)

import time

def myfast():
   code

n = 10000
t0 = time.time()
for i in range(n): myfast()
t1 = time.time()

total_n = t1-t0

В Windows, как сказал Кори в комментарии, time.clock() имеет гораздо более высокую точность (микросекунда, а не секунда) и предпочтительнее, чем time.time().

37 голосов
/ 03 марта 2014

Если вы профилируете свой код и можете использовать IPython, он имеет волшебную функцию %timeit.

%%timeit действует на ячейки.

In [2]: %timeit cos(3.14)
10000000 loops, best of 3: 160 ns per loop

In [3]: %%timeit
   ...: cos(3.14)
   ...: x = 2 + 3
   ...: 
10000000 loops, best of 3: 196 ns per loop
32 голосов
/ 19 мая 2010

Совершенно независимо от времени, этот код, который вы показываете, просто неверен: вы выполняете 100 соединений (полностью игнорируя все, кроме последнего), а затем, когда вы делаете первый вызов execute, вы передаете ему локальную переменную query_stmt, которая Вы инициализируете только после вызова выполнения.

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

В частности, если вы хотите, чтобы функция времени работала без параметров и называлась foobar, вы можете использовать timeit.timeit (2.6 или более поздняя версия - более сложная в 2.5 и более ранних версиях):

timeit.timeit('foobar()', number=1000)

Вам лучше указать количество прогонов, потому что значение по умолчанию (миллион) может быть высоким для вашего варианта использования (что приводит к тому, что вы тратите много времени на этот код; -).

7 голосов
/ 26 марта 2016

Фокус на одна конкретная вещь . Дисковый ввод / вывод медленный, поэтому я бы выбрал его из теста, если все, что вы собираетесь настроить, - это запрос к базе данных.

И если вам нужно рассчитать время выполнения вашей базы данных, вместо этого ищите инструменты базы данных, такие как запрос плана запроса, и обратите внимание, что производительность зависит не только от точного запроса и имеющихся у вас индексов, но и от загрузки данных ( сколько данных вы сохранили).

Тем не менее, вы можете просто поместить свой код в функцию и запустить эту функцию с помощью timeit.timeit():

def function_to_repeat():
    # ...

duration = timeit.timeit(function_to_repeat, number=1000)

Это отключит сборку мусора, повторно вызовет функцию function_to_repeat() и определит время общей продолжительности этих вызовов, используя timeit.default_timer(), который является наиболее точным из доступных часов для вашей конкретной платформы.

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

def function_to_repeat(var1, var2):
    # ...

duration = timeit.timeit(
    'function_to_repeat(var1, var2)',
    'from __main__ import function_to_repeat, var1, var2', 
    number=1000)

будет извлекать глобальные переменные function_to_repeat, var1 и var2 из вашего сценария и передавать их в функцию при каждом повторении.

1 голос
/ 19 декабря 2015

Я вижу, что на вопрос уже был дан ответ, но все же хочу добавить мои 2 цента за то же самое.

Я также столкнулся с похожим сценарием, в котором я должен проверить время выполнения для нескольких подходов и поэтому написал небольшой скрипт, который вызывает timeit для всех функций, написанных в нем.

Сценарий также доступен как github gist здесь .

Надеюсь, это поможет вам и другим.

from random import random
import types

def list_without_comprehension():
    l = []
    for i in xrange(1000):
        l.append(int(random()*100 % 100))
    return l

def list_with_comprehension():
    # 1K random numbers between 0 to 100
    l = [int(random()*100 % 100) for _ in xrange(1000)]
    return l


# operations on list_without_comprehension
def sort_list_without_comprehension():
    list_without_comprehension().sort()

def reverse_sort_list_without_comprehension():
    list_without_comprehension().sort(reverse=True)

def sorted_list_without_comprehension():
    sorted(list_without_comprehension())


# operations on list_with_comprehension
def sort_list_with_comprehension():
    list_with_comprehension().sort()

def reverse_sort_list_with_comprehension():
    list_with_comprehension().sort(reverse=True)

def sorted_list_with_comprehension():
    sorted(list_with_comprehension())


def main():
    objs = globals()
    funcs = []
    f = open("timeit_demo.sh", "w+")

    for objname in objs:
        if objname != 'main' and type(objs[objname]) == types.FunctionType:
            funcs.append(objname)
    funcs.sort()
    for func in funcs:
        f.write('''echo "Timing: %(funcname)s"
python -m timeit "import timeit_demo; timeit_demo.%(funcname)s();"\n\n
echo "------------------------------------------------------------"
''' % dict(
                funcname = func,
                )
            )

    f.close()

if __name__ == "__main__":
    main()

    from os import system

    #Works only for *nix platforms
    system("/bin/bash timeit_demo.sh")

    #un-comment below for windows
    #system("cmd timeit_demo.sh")
0 голосов
/ 22 мая 2019

Вот простая оболочка для ответа Стивена.Эта функция не выполняет повторные прогоны / усреднения, просто избавляет вас от необходимости повторять код синхронизации везде:)

'''function which prints the wall time it takes to execute the given command'''
def time_func(func, *args): #*args can take 0 or more 
  import time
  start_time = time.time()
  func(*args)
  end_time = time.time()
  print("it took this long to run: {}".format(end_time-start_time))
...