Python zaman ölçüm işlevi


123

Her işlevde harcanan zamanı test etmek ve adını zamanıyla birlikte yazdırmak için bir python işlevi oluşturmak istiyorum, işlev adını nasıl yazdırabilirim ve bunu yapmanın başka bir yolu varsa lütfen bana söyleyin

def measureTime(a):
    start = time.clock() 
    a()
    elapsed = time.clock()
    elapsed = elapsed - start
    print "Time spent in (function name) is: ", elapsed

Python profil oluşturma araçları size işlev adlarını ve her birinde harcanan zamanı gösterebilir. Burada okuyun: docs.python.org/library/profile.html
Roadmaster

timeitÖlçüm için daha iyi kullanım . Kusursuz değil, ama bıçak ağzınızı açık ara yeniyor ve kullanımı timeitkendiniz daha iyi bir şey yapmaktan çok daha kolay .

Yanıtlar:


241

Birincisi ve en önemlisi, bir profil oluşturucu veya en az kullanım zamanı kullanmanızı şiddetle öneririm .

Bununla birlikte, kesinlikle öğrenmek için kendi zamanlama yönteminizi yazmak istiyorsanız, işte bir dekoratör kullanmaya başlamak için bir yer.

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

Ve kullanımı çok basit, sadece @timing dekoratörünü kullanın:

@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

Not f.func_nameİşlev adını bir dize (Python 2'de) veya f.__name__ Python 3'te almak için arıyorum .


4
tam olarak istediğim şey :) ... ama siz beni python profil oluşturucuyu kullanmaya ikna ettiniz
Wazery

3
Görünüşe göre bu, time.time () öğesinin çağdan bu yana mikrosaniye cinsinden zamanı rapor ettiğini varsayıyor? Belgeler, zamanı saniye cinsinden rapor ettiğini söylüyor . Docs.python.org/2/library/time.html#time.time .
Rahul Jha

Bu, verim işlevinde kullanıldıktan sonra etkili olamaz. Hala bu yöntemi nasıl kullanabilirim ve verimi kullanabilirim?
jiamo

def zamanlama (f): def wrap (* args, ** kwargs): time1 = time.time () ret = f (* args, ** kwargs) time2 = time.time () print '% s işlevi% 0.3 aldı f ms '% (f.func_name, (zaman2-zaman1) * 1000) geri dönüş geri dönüş paketi
Vivek Bagaria

1
kendin yazmanın dezavantajı nedir? Geçen zamanların bir listesini saklamak ve dağılımlarını incelemek yeterince basit değil mi?
3pitt

51

timeitModül ile oynadıktan sonra , aşağıdaki iki yönteme göre çok şık olmayan arayüzünü beğenmedim.

Aşağıdaki kod Python 3'tedir.

Dekoratör yöntemi

Bu, @ Mike'ın yöntemiyle neredeyse aynıdır. İşte ben eklemek kwargsve functoolsdaha iyi hale getirmek için sarın.

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)

Bağlam yöneticisi yöntemi

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)))

Örneğin, bunu şu şekilde kullanabilirsiniz:

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

Ve withblok içindeki kod zamanlanmış olacaktır.

Sonuç

İlk yöntemi kullanarak, normal kodu almak için dekoratör hakkında e-posta yoluyla yorum yapabilirsiniz. Ancak, yalnızca bir işlevi zamanlayabilir. Kodun bir kısmına sahipseniz, onu işlev yapmak için ne yapacağınızı bilmiyorsanız, ikinci yöntemi seçebilirsiniz.

Örneğin, şimdi sahipsin

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

Şimdi bigImage = ...çizgiyi ölçmek istiyorsun . Bunu bir işleve değiştirirseniz, şu olur:

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

Pek harika görünmüyor ... Ya Python 2'deyseniz, nonlocal anahtar kelime 2'deyseniz.

Bunun yerine, ikinci yöntemi kullanmak buraya çok iyi uyuyor:

images = get_images()
with timeit_context('foobar'):
    bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)

İlginç bir katkı, ancak bahsettiğiniz dekoratör yönteminde timeitarayüzü değiştirmeniz ve modülün wraps()işlevini kullanmanız gerektiğini anlamıyorum functools. Demek istediğim, tüm bu ekstra kod gerekli değil.
Billal Begueradj

1
İhtiyaçlarimport functools
Guillaume Chevalier

1
Dekoratörünüzün orijinal işlevin dönüş değerini kaybettiğini unutmayın
Marc Van Daele

11

timeitModüldeki sorunun ne olduğunu anlamıyorum . Muhtemelen bunu yapmanın en basit yolu budur.

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

Fonksiyonlara argümanlar göndermek de mümkündür. Tek ihtiyacınız olan şey, dekoratörleri kullanarak işlevinizi tamamlamak. Burada daha fazla açıklama: http://www.pythoncentral.io/time-a-python-function/

Kendi zamanlama ifadelerinizi yazmakla ilgilenebileceğiniz tek durum, bir işlevi yalnızca bir kez çalıştırmak ve aynı zamanda dönüş değerini elde etmek istemenizdir.

timeitModülü kullanmanın avantajı , yürütme sayısını tekrarlamanıza izin vermesidir. Bu gerekli olabilir, çünkü diğer işlemler zamanlama doğruluğunuzu etkileyebilir. Yani, birden çok kez çalıştırmalı ve en düşük değere bakmalısınız.


3
Sarmalayıcılar ve dekoratörler kullanarak işleve argümanlar mı gönderiyorsunuz? Neden olmasın timeit.timeit(lambda: func(a,b,c), number=1)? Bunu bir terminalde varsayımsal bir çözüm üzerinde test yaparken kullanıyorum.
Jack

11

Timeit'in iki büyük kusuru vardır: işlevin dönüş değerini döndürmez ve içe aktarmalar için fazladan kurulum kodunu iletmeyi gerektiren eval kullanır. Bu, her iki sorunu da basit ve zarif bir şekilde çözer:

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)

Teşekkürler! timeit, Apache Spark ile iyi çalışmıyor çünkü tüm Spark bağımlılıklarını içe aktarmanız gerekiyor ve bunu yapan büyük ve eski bir dizeyi kim yapmak ister? Bu çözüm çok daha basit ve daha esnektir.
Paul

4

Zamanlama için kolay bir araç var. https://github.com/RalphMao/PyTimer

Bir dekoratör gibi çalışabilir :

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

Çıktı:

matmul:0.368434
matmul:2.839355

Ayrıca ad alanı kontrolüne sahip bir eklenti zamanlayıcı gibi çalışabilir (çok sayıda koda sahip olan ve başka herhangi bir yerde çağrılabilen bir işleve ekliyorsanız yararlıdır).

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()                                        

Çıktı:

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

Umarım yardımcı olur


3

Dekoratör Python kitaplığını kullanan dekoratör yöntemi:

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

Blogumdaki gönderiye bakın:

mobilepro.pl Blog'da yayınla

Google Plus'taki gönderim


1

Bunu yapma şeklim:

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."

start = time()Fonksiyonu / döngüleri çalıştırmadan önce printTime(start)ve bloktan hemen sonra olduğu gibi bir değişken ayarlayın .

ve cevabı aldın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.