Fungsi pengukuran waktu Python

123

Saya ingin membuat fungsi python untuk menguji waktu yang dihabiskan di setiap fungsi dan mencetak namanya dengan waktunya, bagaimana saya bisa mencetak nama fungsi dan jika ada cara lain untuk melakukannya tolong beri tahu saya

def measureTime(a):
    start = time.clock() 
    a()
    elapsed = time.clock()
    elapsed = elapsed - start
    print "Time spent in (function name) is: ", elapsed
Wazery
sumber
Alat pembuatan profil Python dapat menunjukkan nama fungsi dan waktu yang dihabiskan di masing-masing fungsi. Baca di sini: docs.python.org/library/profile.html
Roadmaster
Lebih baik digunakan timeituntuk mengukur. Ini tidak sempurna, tetapi jauh lebih baik timeitdaripada tusukan Anda dan jauh lebih mudah digunakan daripada membuat sendiri sesuatu yang lebih baik.

Jawaban:

241

Pertama dan terpenting, saya sangat menyarankan menggunakan profiler atau waktu penggunaan setidaknya .

Namun jika Anda ingin menulis metode pengaturan waktu Anda sendiri hanya untuk belajar, berikut adalah tempat untuk mulai menggunakan dekorator.

Python 2:

def timing(f):
    def wrap(*args):
        time1 = time.time()
        ret = f(*args)
        time2 = time.time()
        print '%s function took %0.3f ms' % (f.func_name, (time2-time1)*1000.0)
        return ret
    return wrap

Dan penggunaannya sangat sederhana, cukup gunakan dekorator @timing:

@timing
def do_work():
  #code

Python 3:

def timing(f):
    def wrap(*args, **kwargs):
        time1 = time.time()
        ret = f(*args, **kwargs)
        time2 = time.time()
        print('{:s} function took {:.3f} ms'.format(f.__name__, (time2-time1)*1000.0))

        return ret
    return wrap

Catatan Saya menelepon f.func_nameuntuk mendapatkan nama fungsi sebagai string (dengan Python 2), atau f.__name__ di Python 3.

Mike Lewis
sumber
4
persis apa yang saya inginkan :) ... tetapi kalian meyakinkan saya untuk menggunakan profiler python
Wazery
3
Sepertinya ini mengasumsikan bahwa time.time () melaporkan waktu dalam mikrodetik sejak epoch? Dokumentasi mengatakan itu melaporkan waktu dalam detik docs.python.org/2/library/time.html#time.time .
Rahul Jha
Ini tidak dapat diterapkan, setelah menggunakan yield in func. Bagaimana saya bisa tetap menggunakan metode ini dan bisa menggunakan hasil?
jiamo
def timing (f): def wrap (* args, ** kwargs): time1 = time.time () ret = f (* args, ** kwargs) time2 = time.time () print '% s fungsi mengambil% 0.3 f ms '% (f.func_name, (time2-time1) * 1000) return ret return wrap
Vivek Bagaria
1
Apa kerugian menulis sendiri? Bukankah menyimpan daftar waktu yang telah berlalu dan memeriksa distribusinya cukup sederhana?
3pitt
51

Setelah bermain dengan timeitmodul, saya tidak suka antarmukanya, yang tidak begitu elegan dibandingkan dengan dua metode berikut.

Kode berikut ada di Python 3.

Metode dekorator

Ini hampir sama dengan metode @ Mike. Disini saya menambahkan kwargsdan functoolsmembungkusnya agar lebih baik.

def timeit(func):
    @functools.wraps(func)
    def newfunc(*args, **kwargs):
        startTime = time.time()
        func(*args, **kwargs)
        elapsedTime = time.time() - startTime
        print('function [{}] finished in {} ms'.format(
            func.__name__, int(elapsedTime * 1000)))
    return newfunc

@timeit
def foobar():
    mike = Person()
    mike.think(30)

Metode manajer konteks

from contextlib import contextmanager

@contextmanager
def timeit_context(name):
    startTime = time.time()
    yield
    elapsedTime = time.time() - startTime
    print('[{}] finished in {} ms'.format(name, int(elapsedTime * 1000)))

Misalnya, Anda dapat menggunakannya seperti:

with timeit_context('My profiling code'):
    mike = Person()
    mike.think()

Dan kode di dalam withblok akan dihitung waktunya.

Kesimpulan

Dengan menggunakan metode pertama, Anda dapat setiap hari mengomentari dekorator untuk mendapatkan kode normal. Namun, itu hanya dapat mengatur waktu suatu fungsi. Jika Anda memiliki beberapa bagian kode yang tidak dapat Anda fungsikan, maka Anda dapat memilih metode kedua.

Misalnya, sekarang Anda punya

images = get_images()
bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)

Sekarang Anda ingin mengatur waktu bigImage = ...antrean. Jika Anda mengubahnya menjadi suatu fungsi, itu akan menjadi:

images = get_images()
bitImage = None
@timeit
def foobar():
    nonlocal bigImage
    bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)

Kelihatannya tidak terlalu bagus ... Bagaimana jika Anda menggunakan Python 2, yang tidak memiliki nonlocalkata kunci.

Sebaliknya, menggunakan metode kedua sangat cocok di sini:

images = get_images()
with timeit_context('foobar'):
    bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)
sinar
sumber
Kontribusi yang menarik, namun saya merasa tidak berguna bahwa dalam metode dekorator yang Anda sebutkan, Anda harus mengubah timeitantarmuka dan menggunakan wraps()fungsi functoolsmodul. Maksud saya semua kode tambahan itu tidak diperlukan.
Billal Begueradj
1
Kebutuhanimport functools
Guillaume Chevalier
1
Perhatikan bahwa dekorator Anda kehilangan nilai hasil dari fungsi aslinya
Marc Van Daele
11

Saya tidak melihat apa masalahnya dengan timeitmodul tersebut. Ini mungkin cara paling sederhana untuk melakukannya.

import timeit
timeit.timeit(a, number=1)

Ini juga memungkinkan untuk mengirim argumen ke fungsi. Yang Anda butuhkan hanyalah menyelesaikan fungsi Anda menggunakan dekorator. Penjelasan lebih lanjut di sini: http://www.pythoncentral.io/time-a-python-function/

Satu-satunya kasus di mana Anda mungkin tertarik untuk menulis pernyataan waktu Anda sendiri adalah jika Anda ingin menjalankan fungsi hanya sekali dan juga ingin mendapatkan nilai kembaliannya.

Keuntungan menggunakan timeitmodul ini adalah memungkinkan Anda mengulangi jumlah eksekusi. Ini mungkin diperlukan karena proses lain mungkin mengganggu keakuratan waktu Anda. Jadi, Anda harus menjalankannya beberapa kali dan melihat nilai terendahnya.

Phani
sumber
3
Mengirim argumen ke fungsi menggunakan pembungkus dan dekorator? Mengapa tidak timeit.timeit(lambda: func(a,b,c), number=1)? Saya menggunakan ini saat melakukan pengujian pada solusi hipotetis di terminal.
Jack
11

Timeit memiliki dua kelemahan besar: ia tidak mengembalikan nilai kembali dari fungsi tersebut, dan ia menggunakan eval, yang mengharuskan diteruskannya kode pengaturan tambahan untuk impor. Ini menyelesaikan kedua masalah dengan sederhana dan elegan:

def timed(f):
  start = time.time()
  ret = f()
  elapsed = time.time() - start
  return ret, elapsed

timed(lambda: database.foo.execute('select count(*) from source.apachelog'))
(<sqlalchemy.engine.result.ResultProxy object at 0x7fd6c20fc690>, 4.07547402381897)
Jonathan Ray
sumber
Terima kasih! timeit tidak bekerja dengan baik dengan Apache Spark karena Anda harus mengimpor semua dependensi Spark, dan siapa yang ingin membuat string lama yang besar yang melakukan itu? Solusi ini jauh lebih sederhana dan lebih fleksibel.
Paul
4

Ada alat yang mudah untuk mengatur waktu. https://github.com/RalphMao/PyTimer

Ini bisa bekerja seperti dekorator :

from pytimer import Timer
@Timer(average=False)      
def matmul(a,b, times=100):
    for i in range(times):
        np.dot(a,b)        

Keluaran:

matmul:0.368434
matmul:2.839355

Ini juga dapat bekerja seperti pengatur waktu plug-in dengan kontrol namespace (berguna jika Anda memasukkannya ke fungsi yang memiliki banyak kode dan dapat dipanggil di mana saja).

timer = Timer()                                           
def any_function():                                       
    timer.start()                                         

    for i in range(10):                                   

        timer.reset()                                     
        np.dot(np.ones((100,1000)), np.zeros((1000,500)))
        timer.checkpoint('block1')                        

        np.dot(np.ones((100,1000)), np.zeros((1000,500)))
        np.dot(np.ones((100,1000)), np.zeros((1000,500)))
        timer.checkpoint('block2')                        
        np.dot(np.ones((100,1000)), np.zeros((1000,1000)))

    for j in range(20):                                   
        np.dot(np.ones((100,1000)), np.zeros((1000,500)))
    timer.summary()                                       

for i in range(2):                                        
    any_function()                                        

Keluaran:

========Timing Summary of Default Timer========
block2:0.065062
block1:0.032529
========Timing Summary of Default Timer========
block2:0.065838
block1:0.032891

Semoga bisa membantu

ralphmao95.dll
sumber
3

Metode dekorator menggunakan pustaka Python dekorator:

import decorator

@decorator
def timing(func, *args, **kwargs):
    '''Function timing wrapper
        Example of using:
        ``@timing()``
    '''

    fn = '%s.%s' % (func.__module__, func.__name__)

    timer = Timer()
    with timer:
        ret = func(*args, **kwargs)

    log.info(u'%s - %0.3f sec' % (fn, timer.duration_in_seconds()))
    return ret

Lihat posting di Blog saya:

posting di Blog mobilepro.pl

posting saya di Google Plus

MobilePro.pl
sumber
1

Cara saya melakukannya:

from time import time

def printTime(start):
    end = time()
    duration = end - start
    if duration < 60:
        return "used: " + str(round(duration, 2)) + "s."
    else:
        mins = int(duration / 60)
        secs = round(duration % 60, 2)
        if mins < 60:
            return "used: " + str(mins) + "m " + str(secs) + "s."
        else:
            hours = int(duration / 3600)
            mins = mins % 60
            return "used: " + str(hours) + "h " + str(mins) + "m " + str(secs) + "s."

Tetapkan variabel seperti start = time()sebelum menjalankan fungsi / loop, dan printTime(start)tepat setelah blok.

dan Anda mendapat jawabannya.

Adam Liu
sumber