Matlab'ın tik ve toc işlevlerinin Python eşdeğeri nedir?


112

Matlab'ın tik ve toc işlevlerinin Python eşdeğeri nedir ?


7
Doğrudan eşdeğerini gerçekten istiyorsanız, sadece arayın tic = time.time()ve toc = time.time()ardından print toc-tic, 'sec Elapsed', aşağıda insanların söylediği gibi, yine timeitde daha sağlamdır.
Joe Kington

@ JoeKington'ın yaklaşımını timeit.default_timer () ile birlikte kullanarak daha iyi sonuçlar elde ediyorum, örneğin şöyle:, tic = timeit.default_timer(); (U,S,V) = np.linalg.svd(A); toc = timeit.default_timer()o zaman print toc-tic.
littleO

1
Pytictoc kütüphanesi en uygun görünmektedir, sözdizimi aşağıdaki ttictoc'tan biraz daha temizdir. pypi.org/project/pytictoc
FlorianH

Yanıtlar:


172

timeitThiefMaster'ın bahsettiğinin dışında, bunu yapmanın basit bir yolu (içe aktardıktan sonra time):

t = time.time()
# do stuff
elapsed = time.time() - t

Kullanmayı sevdiğim yardımcı bir sınıfım var:

class Timer(object):
    def __init__(self, name=None):
        self.name = name

    def __enter__(self):
        self.tstart = time.time()

    def __exit__(self, type, value, traceback):
        if self.name:
            print('[%s]' % self.name,)
        print('Elapsed: %s' % (time.time() - self.tstart))

Bir bağlam yöneticisi olarak kullanılabilir:

with Timer('foo_stuff'):
   # do some foo
   # do some stuff

Bazen bu tekniği daha uygun buluyorum timeit- hepsi ölçmek istediğiniz şeye bağlı.


25
@eat: Saygıyla katılmıyorum. İnsanlar timesonsuza dek programların çalışma zamanlarını ölçmek için unix komutunu kullanıyorlar ve bu yöntem bunu Python kodu içinde çoğaltır. İş için doğru araç olduğu sürece bunda yanlış bir şey görmüyorum. timeither zaman böyle değildir ve profil oluşturucu çoğu ihtiyaç için çok daha ağır bir çözümdür
Eli Bendersky

4
Son satır için tavsiye ederim print 'Elapsed: %.2f seconds % (time.time() - self.tstart)'. % .2f olmadan anlamak zor. Harika fikir için teşekkürler.
Can Kavaklıoğlu

4
Bu, ilk bakışta çok uygun görünür, ancak pratikte, kişinin zamanlamak istediği kod bloğunu girintilendirmesini gerektirir, bu, kod bloğunun uzunluğuna ve tercih edilen düzenleyiciye bağlı olarak oldukça rahatsız edici olabilir. Yine de iç içe kullanım durumunda doğru şekilde davranan zarif bir çözüm.
Stefan

1
Bunun elapsed = t - time.time()yerine istediğini düşünüyorum elapsed = time.time() - t. İkincisi geçen süre negatif olacaktır. Bu değişikliği bir düzenleme olarak önerdim.
rysqui

3
@rysqui - Şu anki saat her zaman bir önceki zamandan daha büyük bir sayı değil mi? Bence bu elapsed = time.time() - ther zaman pozitif bir değer veren formdur.
Scott Smith

32

Matlab'dan python'a geçerken de aynı soruyu sormuştum. Bu iş parçacığının yardımıyla Matlab'ın ve fonksiyonlarının tam bir benzerini oluşturabildim . Aşağıdaki kodu komut dosyanızın en üstüne eklemeniz yeterlidir.tic()toc()

import time

def TicTocGenerator():
    # Generator that returns time differences
    ti = 0           # initial time
    tf = time.time() # final time
    while True:
        ti = tf
        tf = time.time()
        yield tf-ti # returns the time difference

TicToc = TicTocGenerator() # create an instance of the TicTocGen generator

# This will be the main function through which we define both tic() and toc()
def toc(tempBool=True):
    # Prints the time difference yielded by generator instance TicToc
    tempTimeInterval = next(TicToc)
    if tempBool:
        print( "Elapsed time: %f seconds.\n" %tempTimeInterval )

def tic():
    # Records a time in TicToc, marks the beginning of a time interval
    toc(False)

Bu kadar! Şimdi tamamen kullanıma hazır tic()ve toc()sadece Matlabda olarak. Örneğin

tic()

time.sleep(5)

toc() # returns "Elapsed time: 5.00 seconds."

Aslında bu, yerleşik Matlab işlevlerinden daha çok yönlüdür. Burada, TicTocGeneratorbirden çok işlemi takip etmek için veya sadece işleri farklı şekilde zamanlamak için başka bir örnek oluşturabilirsiniz . Örneğin, bir komut dosyasını zamanlarken, artık komut dosyasının her parçasını ve tüm komut dosyasını ayrı ayrı ölçebiliriz. (Somut bir örnek vereceğim)

TicToc2 = TicTocGenerator() # create another instance of the TicTocGen generator

def toc2(tempBool=True):
    # Prints the time difference yielded by generator instance TicToc2
    tempTimeInterval = next(TicToc2)
    if tempBool:
    print( "Elapsed time 2: %f seconds.\n" %tempTimeInterval )

def tic2():
    # Records a time in TicToc2, marks the beginning of a time interval
    toc2(False)

Şimdi iki ayrı şeyi zamanlayabilmelisiniz: Aşağıdaki örnekte, toplam komut dosyası ve bir komut dosyasının bölümlerini ayrı ayrı ölçüyoruz.

tic()

time.sleep(5)

tic2()

time.sleep(3)

toc2() # returns "Elapsed time 2: 5.00 seconds."

toc() # returns "Elapsed time: 8.00 seconds."

Aslında tic()her seferinde kullanmanıza bile gerek yok . Zamanlamak istediğiniz bir dizi komutunuz varsa, yazabilirsiniz

tic()

time.sleep(1)

toc() # returns "Elapsed time: 1.00 seconds."

time.sleep(2)

toc() # returns "Elapsed time: 2.00 seconds."

time.sleep(3)

toc() # returns "Elapsed time: 3.00 seconds."

# and so on...

Umarım bu yardımcı olur.


22

Tic ve toc'un mutlak en iyi analoğu, onları python'da basitçe tanımlamak olacaktır.

def tic():
    #Homemade version of matlab tic and toc functions
    import time
    global startTime_for_tictoc
    startTime_for_tictoc = time.time()

def toc():
    import time
    if 'startTime_for_tictoc' in globals():
        print "Elapsed time is " + str(time.time() - startTime_for_tictoc) + " seconds."
    else:
        print "Toc: start time not set"

O zaman bunları şu şekilde kullanabilirsiniz:

tic()
# do stuff
toc()

6
Matlab'ın desteklediği ticve iç içe kullanım durumunda bu doğru davranmayacaktır toc. Biraz daha karmaşıklık gerekli olacaktır.
Stefan

2
Bazı temel zamanlamaya ihtiyaç duyduğumda kendi kodumda benzer işlevleri uyguladım. Bununla birlikte import time, potansiyel olarak biraz zaman alabileceğinden, her iki işlevin dışını da kaldırırım .
Bas Swinckels

Bu tekniği kullanmakta ısrar ediyorsanız ve iç içe geçmiş tic / toc'u işlemeye ihtiyacınız varsa, global bir liste yapın ve ticonu itip çıkmasına izin verin toc.
Ahmed Fasih

1
Ayrıca ben başka bir yerde okumak timeit.default_timer()daha iyi olduğunu time.time()çünkü time.clock()OS bağlı olarak daha uygun olabilir
Miguel

@AhmedFasih Cevabım budur, ancak daha fazla şey geliştirilebilir.
antonimmo

15

Genellikle ipython en %time, %timeit, %prunve %lprun(bir eğer line_profileryüklü) oldukça iyi benim profilleme ihtiyaçlarını karşılamak. Bununla birlikte, tic-tocetkileşimli olarak, yani bir GUI'de kullanıcının fare hareketi tarafından yönlendirilen hesaplamaların profilini çıkarmaya çalıştığımda, benzer işlevsellik için bir kullanım durumu ortaya çıktı. Ben spam gibi hissettim ticler ve tocetkileşimli test darboğazları ortaya çıkarmak için hızlı yolu olacağını ise kaynaklarda s. Eli Bendersky'nin Timersınıfıyla gittim , ancak kodumun girintisini değiştirmemi gerektirdiğinden, bazı editörlerde rahatsız edici olabilecek ve sürüm kontrol sistemini karıştırdığı için tam olarak mutlu değildim. Dahası, farklı işlevlerdeki noktalar arasındaki zamanı ölçme ihtiyacı olabilir ve bu,withBeyan. Pek çok Python zekasını denedikten sonra, işte bulduğum basit çözüm en iyi sonucu verdi:

from time import time
_tstart_stack = []

def tic():
    _tstart_stack.append(time())

def toc(fmt="Elapsed: %s s"):
    print fmt % (time() - _tstart_stack.pop())

Bu, bir yığındaki başlangıç ​​zamanlarını iterek çalıştığından, birden çok düzeydeki tics ve tocs için doğru şekilde çalışacaktır . Ayrıca toc, Eli'nin Timersınıfı hakkında sevdiğim ek bilgileri görüntülemek için ifadenin biçim dizesini değiştirmeye izin veriyor .

Bazı nedenlerden dolayı saf bir Python uygulamasının ek yüküyle ilgileniyordum, bu yüzden bir C genişletme modülünü de test ettim:

#include <Python.h>
#include <mach/mach_time.h>
#define MAXDEPTH 100

uint64_t start[MAXDEPTH];
int lvl=0;

static PyObject* tic(PyObject *self, PyObject *args) {
    start[lvl++] = mach_absolute_time();
    Py_RETURN_NONE;
}

static PyObject* toc(PyObject *self, PyObject *args) {
return PyFloat_FromDouble(
        (double)(mach_absolute_time() - start[--lvl]) / 1000000000L);
}

static PyObject* res(PyObject *self, PyObject *args) {
    return tic(NULL, NULL), toc(NULL, NULL);
}

static PyMethodDef methods[] = {
    {"tic", tic, METH_NOARGS, "Start timer"},
    {"toc", toc, METH_NOARGS, "Stop timer"},
    {"res", res, METH_NOARGS, "Test timer resolution"},
    {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
inittictoc(void) {
    Py_InitModule("tictoc", methods);
}

Bu, MacOSX içindir ve lvlkısalık açısından sınırların dışında olup olmadığını kontrol etmek için kodu atladım. İken tictoc.res()verim sistemimde yaklaşık 50 nanosaniye çözünürlük, ben (ipython gelen kullanıldığında çok daha ve) Herhangi bir Python deyimini ölçme titreşim mikrosaniye aralığında kolayca tespit ettik. Bu noktada, Python uygulamasının ek yükü ihmal edilebilir hale gelir, böylece C uygulamasıyla aynı güvenle kullanılabilir.

tic-toc-Yaklaşımının kullanışlılığının, yürütmesi 10 mikrosaniyeden fazla süren kod bloklarıyla sınırlı olduğunu buldum . Bunun altında, timeitgüvenilir bir ölçüm elde etmek için in gibi ortalama stratejileri gereklidir.


1
Son derece zarif, @Stefan - bunun bu kadar düşük puanlı olduğuna inanamıyorum. Teşekkürler!
thclark

10

ticVe tocile kullanabilirsiniz ttictoc. İle yükleyin

pip install ttictoc

Ve bunları komut dosyanıza aşağıdaki gibi içe aktarın

from ttictoc import tic,toc
tic()
# Some code
print(toc())

8

Matlab'ın yaptığı gibi iç içe geçmiş tic tocs elde etmek için bir modül [tictoc.py] oluşturdum.

from time import time

tics = []

def tic():
    tics.append(time())

def toc():
    if len(tics)==0:
        return None
    else:
        return time()-tics.pop()

Ve şu şekilde çalışır:

from tictoc import tic, toc

# This keeps track of the whole process
tic()

# Timing a small portion of code (maybe a loop)
tic()

# -- Nested code here --

# End
toc()  # This returns the elapse time (in seconds) since the last invocation of tic()
toc()  # This does the same for the first tic()

Umut ediyorum bu yardım eder.


MATLAB'dan güzel tic / toc kopyası!
Matt

1
(AFAIK) modülleri tekil gibi davrandığından, 1'den fazla modül tarafından aynı anda kullanıldığında istenildiği gibi davranmayabileceği konusunda sizi uyarmalıyım.
antonimmo

3

timeitModüle bir göz atın . Gerçekten eşdeğer değil ama zamanını almak istediğiniz kod bir işlevin içindeyse, onu kolayca kullanabilirsiniz.


Evet, timeitkıyaslamalar için en iyisidir. Tek bir işlev olmak zorunda bile değil, sürekli olarak karmaşık ifadeler iletebilirsiniz.

10
Pekala, son derece basit bir işlev çağrısı olmayan kodu bir dizge olarak geçirmek çok çirkin.
ThiefMaster


1

Bu aynı zamanda bir sarmalayıcı kullanılarak da yapılabilir. Zamanı tutmanın çok genel bir yolu.

Bu örnek koddaki sarmalayıcı, herhangi bir işlevi sarar ve işlevi yürütmek için gereken süreyi yazdırır:

def timethis(f):
    import time

    def wrapped(*args, **kwargs):
        start = time.time()
        r = f(*args, **kwargs)
        print "Executing {0} took {1} seconds".format(f.func_name,  time.time()-start)
        return r
    return wrapped

@timethis
def thistakestime():
    for x in range(10000000):
        pass

thistakestime()

Sarmalayıcı işlevi, zamanbu bir dekoratör olarak adlandırılır. Biraz daha ayrıntılı açıklama burada: medium.com/pythonhive/…
Mircea

1

@Eli Bendersky'nin cevabını , zamanlamayı yapmak için ctor __init__()ve dtor'u kullanmak için biraz değiştirdim __del__(), böylece orijinal kodu girmeden daha rahat bir şekilde kullanılabilir:

class Timer(object):
    def __init__(self, name=None):
        self.name = name
        self.tstart = time.time()

    def __del__(self):
        if self.name:
            print '%s elapsed: %.2fs' % (self.name, time.time() - self.tstart)
        else:
            print 'Elapsed: %.2fs' % (time.time() - self.tstart)

Kullanmak için, Timer'ı ("blahblah") bazı yerel kapsamların başına koyun. Geçen süre kapsamın sonunda yazdırılacaktır:

for i in xrange(5):
    timer = Timer("eigh()")
    x = numpy.random.random((4000,4000));
    x = (x+x.T)/2
    numpy.linalg.eigh(x)
    print i+1
timer = None

Çıktı:

1
eigh() elapsed: 10.13s
2
eigh() elapsed: 9.74s
3
eigh() elapsed: 10.70s
4
eigh() elapsed: 10.25s
5
eigh() elapsed: 11.28s

3
Bu uygulamayla ilgili bir sorun timer, fordöngüden sonra başka bir kod izlerse, son çağrıdan sonra silinmemesidir . Son zamanlayıcı değerini elde etmek timeriçin fordöngüden sonra silinmeli veya üzerine yazılmalıdır , örn timer = None.
bastelflp

1
@bastelflp Ne demek istediğini yanlış anladığımı anladım ... Öneriniz şimdi koda eklenmiştir. Teşekkürler.
Shaohua Li

1

Eli'nin Python 3'e cevabını güncelleme :

class Timer(object):
    def __init__(self, name=None, filename=None):
        self.name = name
        self.filename = filename

    def __enter__(self):
        self.tstart = time.time()

    def __exit__(self, type, value, traceback):
        message = 'Elapsed: %.2f seconds' % (time.time() - self.tstart)
        if self.name:
            message = '[%s] ' % self.name + message
        print(message)
        if self.filename:
            with open(self.filename,'a') as file:
                print(str(datetime.datetime.now())+": ",message,file=file)

Eli'ninki gibi, bir bağlam yöneticisi olarak kullanılabilir:

import time 
with Timer('Count'):
    for i in range(0,10_000_000):
        pass

Çıktı:

[Count] Elapsed: 0.27 seconds

Ayrıca, Can'ın önerdiği şekilde bildirilen zaman birimlerini (saniye) yazdırmak ve basamak sayısını kırpmak ve ayrıca bir günlük dosyasına ekleme seçeneği ile güncelledim. Günlük özelliğini kullanmak için tarih saatini içe aktarmanız gerekir:

import time
import datetime 
with Timer('Count', 'log.txt'):    
    for i in range(0,10_000_000):
        pass

0

Stefan ve antonimmo'nun yanıtlarına dayanarak,

def Tictoc():
    start_stack = []
    start_named = {}

    def tic(name=None):
        if name is None:
            start_stack.append(time())
        else:
            start_named[name] = time()

    def toc(name=None):
        if name is None:
            start = start_stack.pop()
        else:
            start = start_named.pop(name)
        elapsed = time() - start
        return elapsed
    return tic, toc

bir utils.pymodülde ve bunu bir

from utils import Tictoc
tic, toc = Tictoc()

Bu yoldan

  • basitçe kullanabilirsiniz tic(), toc()ve yuva onları Matlabda gibi
  • alternatif olarak, bunları adlandırabilir: tic(1), toc(1)veya tic('very-important-block'), toc('very-important-block')ve farklı isimlerle zamanlayıcılar engel olmaz
  • bunları bu şekilde içe aktarmak, onu kullanan modüller arasında girişimi önler.

(burada toc geçen süreyi yazdırmaz, ancak onu döndürür.)

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.