Apa persamaan Python dari fungsi tic dan toc Matlab?


112

Apa persamaan Python dari fungsi tic dan toc Matlab ?


7
Jika Anda benar-benar menginginkan padanan langsung, panggil saja tic = time.time()dan toc = time.time(), seperti yang print toc-tic, 'sec Elapsed'dikatakan orang di bawah ini, timeitlebih kuat.
Joe Kington

Saya tampaknya mendapatkan hasil yang lebih baik menggunakan pendekatan @ JoeKington dalam hubungannya dengan timeit.default_timer (), seperti ini misalnya:, tic = timeit.default_timer(); (U,S,V) = np.linalg.svd(A); toc = timeit.default_timer()lalu print toc-tic.
littleO

1
Pytictoc perpustakaan tampaknya paling meyakinkan, sintaksnya bahkan sedikit lebih rapi daripada ttictoc di bawah ini. pypi.org/project/pytictoc
FlorianH

Jawaban:


172

Selain timeityang disebutkan ThiefMaster, cara sederhana untuk melakukannya adalah (setelah mengimpor time):

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

Saya memiliki kelas helper yang saya suka gunakan:

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

Ini dapat digunakan sebagai manajer konteks:

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

Kadang-kadang saya merasa teknik ini lebih nyaman daripada timeit- semuanya tergantung pada apa yang ingin Anda ukur.


25
@ Makan: Saya dengan hormat tidak setuju. Orang-orang telah menggunakan timeperintah unix untuk mengukur runtime program untuk selamanya, dan metode ini mereplikasi ini di dalam kode Python. Saya tidak melihat ada yang salah dengan itu, selama itu alat yang tepat untuk pekerjaan itu. timeittidak selalu begitu, dan profiler adalah solusi kelas berat yang jauh lebih berat untuk sebagian besar kebutuhan
Eli Bendersky

4
Untuk baris terakhir saya sarankan print 'Elapsed: %.2f seconds % (time.time() - self.tstart)'. Sulit untuk memahami tanpa% .2f. Terima kasih untuk ide yang bagus.
Bisakah Kavaklıoğlu

4
Ini terlihat sangat nyaman pada pandangan pertama, tetapi dalam praktiknya mengharuskan seseorang untuk mengindentasi blok kode yang diinginkan sesuai waktu, yang bisa sangat merepotkan tergantung pada panjang blok kode dan editor pilihan. Masih merupakan solusi elegan, yang berperilaku dengan benar dalam kasus penggunaan bersarang.
Stefan

1
Saya pikir Anda ingin elapsed = t - time.time(), bukan elapsed = time.time() - t. Yang terakhir berlalu akan menjadi negatif. Saya menyarankan perubahan ini sebagai edit.
rysqui

3
@rysqui - Bukankah waktu saat ini selalu lebih besar dari waktu sebelumnya ? Menurut saya elapsed = time.time() - t, bentuk itulah yang selalu menghasilkan nilai positif.
Scott Smith

32

Saya memiliki pertanyaan yang sama ketika saya bermigrasi ke python dari Matlab. Dengan bantuan utas ini saya dapat membuat analog yang tepat dari Matlab tic()dan toc()fungsi. Cukup masukkan kode berikut di bagian atas skrip Anda.

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)

Itu dia! Sekarang kami siap untuk menggunakan sepenuhnya tic()dan toc()seperti di Matlab. Sebagai contoh

tic()

time.sleep(5)

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

Sebenarnya, ini lebih serbaguna daripada fungsi Matlab bawaan. Di sini, Anda dapat membuat contoh lain TicTocGeneratoruntuk melacak beberapa operasi, atau hanya mengatur waktu secara berbeda. Misalnya, saat mengatur waktu skrip, sekarang kita dapat menentukan waktu setiap bagian skrip secara terpisah, serta seluruh skrip. (Saya akan memberikan contoh konkret)

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)

Sekarang Anda seharusnya dapat mengatur waktu dua hal yang terpisah: Dalam contoh berikut, kita menghitung waktu total skrip dan bagian skrip secara terpisah.

tic()

time.sleep(5)

tic2()

time.sleep(3)

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

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

Sebenarnya, Anda bahkan tidak perlu menggunakannya tic() setiap saat. Jika Anda memiliki serangkaian perintah yang Anda ingin waktu, maka Anda dapat menulis

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

Saya harap ini membantu.


22

Analog terbaik mutlak dari tic dan toc adalah dengan mendefinisikannya dengan python.

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"

Kemudian Anda dapat menggunakannya sebagai:

tic()
# do stuff
toc()

6
Ini tidak akan berperilaku dengan benar dalam kasus penggunaan bersarang ticdan toc, yang didukung Matlab. Diperlukan sedikit lebih banyak kecanggihan.
Stefan

2
Saya telah menerapkan fungsi serupa dalam kode saya sendiri ketika saya membutuhkan waktu dasar. Namun saya akan menghapus bagian import timeluar kedua fungsi, karena ini bisa memakan waktu cukup lama.
Bas Swinckels

Jika Anda bersikeras menggunakan teknik ini, dan Anda membutuhkannya untuk menangani tic / toc bersarang, buat daftar global dan biarkan ticmendorong ke sana dan keluar tocdarinya.
Ahmed Fasih

1
Juga saya membaca di tempat lain yang timeit.default_timer()lebih baik daripada time.time()karena time.clock()mungkin lebih sesuai tergantung pada OS
Miguel

@AhmedFasih Itulah jawaban saya, meski lebih banyak hal yang bisa ditingkatkan.
antonimmo

15

Biasanya, IPython ini %time, %timeit, %prundan %lprun(jika telah line_profilerdiinstal) memenuhi kebutuhan profil saya cukup baik. Namun, kasus penggunaan untuk tic-tocfungsionalitas -seperti muncul ketika saya mencoba membuat profil kalkulasi yang didorong secara interaktif, yaitu, oleh gerakan mouse pengguna di GUI. Saya merasa ingin melakukan spamming ticdantoc s di sumber sementara pengujian interaktif akan menjadi cara tercepat untuk mengungkap kemacetan. Saya mengikuti Timerkelas Eli Bendersky , tetapi tidak sepenuhnya senang, karena itu mengharuskan saya untuk mengubah lekukan kode saya, yang dapat merepotkan di beberapa editor dan membingungkan sistem kontrol versi. Selain itu, mungkin ada kebutuhan untuk mengukur waktu antar titik dalam fungsi yang berbeda, yang tidak akan berfungsi denganwithpernyataan. Setelah mencoba banyak kecerdasan Python, berikut adalah solusi sederhana yang menurut saya paling berhasil:

from time import time
_tstart_stack = []

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

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

Karena ini bekerja dengan mendorong waktu mulai pada tumpukan, ini akan bekerja dengan benar untuk beberapa level tics dan tocs. Ini juga memungkinkan seseorang untuk mengubah string format tocpernyataan untuk menampilkan informasi tambahan, yang saya suka tentang Timerkelas Eli .

Untuk beberapa alasan saya khawatir dengan overhead dari implementasi Python murni, jadi saya menguji modul ekstensi C juga:

#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);
}

Ini untuk MacOSX, dan saya telah menghilangkan kode untuk memeriksa apakah di lvlluar batas untuk singkatnya. Sementara tictoc.res()menghasilkan resolusi sekitar 50 nanodetik di sistem saya, saya menemukan bahwa jitter dalam mengukur pernyataan Python apa pun dengan mudah berada dalam kisaran mikrodetik (dan lebih banyak lagi bila digunakan dari IPython). Pada titik ini, overhead implementasi Python menjadi dapat diabaikan, sehingga dapat digunakan dengan tingkat kepercayaan yang sama seperti implementasi C.

Saya menemukan bahwa kegunaan tic-toc-approach secara praktis terbatas pada blok kode yang membutuhkan lebih dari 10 mikrodetik untuk dieksekusi. Di bawah itu, diperlukan strategi rata-rata seperti in timeituntuk mendapatkan ukuran yang tepat.


1
Sangat elegan, @Stefan - tidak percaya peringkat ini sangat rendah. Terima kasih!
thclark

10

Anda dapat menggunakan ticdan tocdari ttictoc. Instal dengan

pip install ttictoc

Dan impor saja di skrip Anda sebagai berikut

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

8

Saya baru saja membuat modul [tictoc.py] untuk mencapai tic tocs bersarang, yang dilakukan oleh Matlab.

from time import time

tics = []

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

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

Dan cara kerjanya seperti ini:

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

Saya harap ini membantu.


Replikasi bagus tic / toc dari MATLAB!
Matt

1
Saya harus memperingatkan Anda bahwa ini mungkin tidak berperilaku seperti yang diinginkan bila digunakan secara bersamaan oleh lebih dari 1 modul, karena modul (AFAIK) berperilaku seperti lajang.
antonimmo

3

Lihat timeitmodulnya. Ini tidak benar-benar setara tetapi jika kode yang Anda inginkan waktu ada di dalam fungsi, Anda dapat dengan mudah menggunakannya.


Ya, timeityang terbaik untuk tolok ukur. Ia bahkan tidak harus menjadi satu fungsi, Anda dapat memberikan pernyataan yang sangat rumit.

10
Nah, melewatkan kode yang bukan merupakan pemanggilan fungsi yang sangat sederhana sebagai string sangat jelek.
ThiefMaster


1

Ini juga bisa dilakukan dengan menggunakan pembungkus. Cara yang sangat umum untuk menghitung waktu.

Wrapper dalam kode contoh ini membungkus fungsi apa pun dan mencetak jumlah waktu yang diperlukan untuk menjalankan fungsi tersebut:

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

Fungsi pembungkus, waktu ini disebut sebagai dekorator. Penjelasan yang sedikit lebih detail, di sini: medium.com/pythonhive/…
Mircea

1

Saya mengubah jawaban @Eli Bendersky sedikit untuk menggunakan ctor __init__()dan dtor __del__()untuk melakukan pengaturan waktu, sehingga dapat digunakan dengan lebih nyaman tanpa memasukkan kode aslinya:

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)

Untuk menggunakannya, letakkan Timer ("bla bla") di awal beberapa lingkup lokal. Waktu yang berlalu akan dicetak di akhir ruang lingkup:

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

Ini mencetak:

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
Masalah dengan implementasi ini adalah fakta, yang timertidak dihapus setelah panggilan terakhir, jika kode lain mengikuti setelah forloop. Untuk mendapatkan nilai timer terakhir, seseorang harus menghapus atau menimpa loop timersetelahnya for, misalnya via timer = None.
bastelflp

1
@bastelflp Baru menyadari bahwa saya salah paham apa yang Anda maksud ... Saran Anda telah dimasukkan ke dalam kode sekarang. Terima kasih.
Shaohua Li

1

Memperbarui jawaban Eli untuk Python 3:

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)

Sama seperti Eli, ini dapat digunakan sebagai manajer konteks:

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

Keluaran:

[Count] Elapsed: 0.27 seconds

Saya juga telah memperbaruinya untuk mencetak satuan waktu yang dilaporkan (detik) dan memangkas jumlah digit seperti yang disarankan oleh Can, dan dengan opsi untuk juga menambahkan ke file log. Anda harus mengimpor datetime untuk menggunakan fitur logging:

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

0

Berdasarkan jawaban Stefan dan antonimmo, saya akhirnya meletakkan

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

dalam utils.pymodul, dan saya menggunakannya dengan file

from utils import Tictoc
tic, toc = Tictoc()

Cara ini

  • Anda cukup menggunakan tic(), toc()dan menyarangkannya seperti di Matlab
  • alternatif, Anda dapat nama mereka: tic(1), toc(1)atau tic('very-important-block'), toc('very-important-block')dan timer dengan nama yang berbeda tidak akan mengganggu
  • mengimpornya dengan cara ini mencegah interferensi antar modul yang menggunakannya.

(di sini toc tidak mencetak waktu yang telah berlalu, tetapi mengembalikannya.)

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.