Python tương đương với các hàm tic và toc của Matlab là gì?


112

Python tương đương với các hàm tic và toc của Matlab là gì?


7
Tuy nhiên, nếu bạn thực sự muốn tương đương trực tiếp, chỉ cần gọi tic = time.time()toc = time.time(), sau đó print toc-tic, 'sec Elapsed'Như mọi người đã nói bên dưới, timeitmạnh mẽ hơn.
Joe Kington

Tôi dường như nhận được kết quả tốt hơn bằng cách sử dụng phương pháp của @ JoeKington kết hợp với timeit.default_timer (), ví dụ như thế này:, tic = timeit.default_timer(); (U,S,V) = np.linalg.svd(A); toc = timeit.default_timer()sau đó print toc-tic.
littleO

1
Thư viện pytictoc có vẻ dễ hiểu nhất, cú pháp thậm chí còn gọn gàng hơn một chút so với ttictoc bên dưới. pypi.org/project/pytictoc
FlorianH

Câu trả lời:


172

Ngoài timeitnhững gì ThiefMaster đã đề cập, một cách đơn giản để làm điều đó chỉ là (sau khi nhập time):

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

Tôi có một lớp trợ giúp mà tôi muốn sử dụng:

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

Nó có thể được sử dụng như một trình quản lý ngữ cảnh:

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

Đôi khi tôi thấy kỹ thuật này thuận tiện hơn timeit- tất cả phụ thuộc vào những gì bạn muốn đo.


25
@eat: Tôi xin trân trọng không đồng ý. Mọi người đã sử dụng timelệnh unix để đo thời gian chạy của các chương trình và phương pháp này sao chép điều này bên trong mã Python. Tôi thấy nó không có gì sai, miễn là nó là công cụ phù hợp với công việc. timeitkhông phải lúc nào đó, và một hồ sơ là một giải pháp nhiều nặng hơn đối với hầu hết nhu cầu
Eli Bendersky

4
Đối với dòng cuối cùng tôi sẽ đề nghị print 'Elapsed: %.2f seconds % (time.time() - self.tstart)'. Thật khó hiểu nếu không có% .2f. Cảm ơn vì ý tưởng tuyệt vời.
Có thể Kavaklıoğlu

4
Điều này thoạt nhìn trông rất tiện lợi, nhưng trong thực tế, người ta yêu cầu phải thụt lề khối mã mà người ta muốn căn thời gian, điều này có thể khá bất tiện tùy thuộc vào độ dài của khối mã và trình soạn thảo lựa chọn. Vẫn là một giải pháp thanh lịch, hoạt động chính xác trong trường hợp sử dụng lồng nhau.
Stefan

1
Tôi nghĩ bạn muốn elapsed = t - time.time(), thay vì elapsed = time.time() - t. Trong phần sau trôi qua sẽ là tiêu cực. Tôi đã đề xuất thay đổi này như một chỉnh sửa.
rysqui

3
@rysqui - Không phải thời điểm hiện tại luôn là một con số lớn hơn thời điểm trước đó sao? Tôi nghĩ đó elapsed = time.time() - tlà biểu mẫu luôn mang lại giá trị dương.
Scott Smith

32

Tôi có cùng một câu hỏi khi chuyển sang python từ Matlab. Với sự trợ giúp của chủ đề này, tôi đã có thể xây dựng một tương tự chính xác của Matlab tic()và các toc()hàm. Chỉ cần chèn mã sau vào đầu tập lệnh của bạn.

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)

Đó là nó! Bây giờ chúng tôi đã sẵn sàng để sử dụng đầy đủ tic()toc()giống như trong Matlab. Ví dụ

tic()

time.sleep(5)

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

Trên thực tế, điều này linh hoạt hơn các chức năng Matlab tích hợp sẵn. Tại đây, bạn có thể tạo một phiên bản khác của biểu tượng TicTocGeneratorđể theo dõi nhiều hoạt động hoặc chỉ để tính giờ mọi thứ theo cách khác. Ví dụ, trong khi định thời gian cho một tập lệnh, giờ đây chúng ta có thể định thời gian cho từng đoạn của tập lệnh một cách riêng biệt, cũng như toàn bộ tập lệnh. (Tôi sẽ cung cấp một ví dụ cụ thể)

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)

Bây giờ bạn sẽ có thể tính thời gian cho hai việc riêng biệt: Trong ví dụ sau, chúng tôi tính thời gian cho tổng tập lệnh và các phần của tập lệnh một cách riêng biệt.

tic()

time.sleep(5)

tic2()

time.sleep(3)

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

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

Trên thực tế, bạn thậm chí không cần phải sử dụng tic()mỗi lần. Nếu bạn có một loạt lệnh mà bạn muốn bấm giờ, thì bạn có thể viết

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

Tôi hy vọng rằng điều này là hữu ích.


22

Tương tự tốt nhất tuyệt đối của tic và toc sẽ chỉ đơn giản là xác định chúng trong 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"

Sau đó, bạn có thể sử dụng chúng như:

tic()
# do stuff
toc()

6
Điều này sẽ không hoạt động chính xác trong trường hợp sử dụng lồng nhau của tictoc, mà Matlab hỗ trợ. Một chút tinh tế sẽ được yêu cầu.
Stefan

2
Tôi đã triển khai các chức năng tương tự trong mã của riêng mình khi tôi cần một số thời gian cơ bản. Tuy nhiên, tôi sẽ xóa import timebên ngoài của cả hai chức năng, vì nó có thể mất một khoảng thời gian.
Bas Swinckels

Nếu bạn kiên quyết sử dụng kỹ thuật này và bạn cần nó để xử lý tic / toc lồng nhau, hãy tạo danh sách chung cho toàn cục và ticđẩy nó đến và tocbật ra khỏi nó.
Ahmed Fasih

1
Ngoài ra tôi đọc ở đâu đó rằng timeit.default_timer()là tốt hơn so với time.time()time.clock()có thể thích hợp hơn tùy thuộc vào hệ điều hành
Miguel

@AhmedFasih Đó là câu trả lời của tôi, mặc dù nhiều thứ có thể được cải thiện.
antonimmo

15

Thông thường, IPython của %time, %timeit, %prun%lprun(nếu ai đã line_profilercài đặt) đáp ứng nhu cầu profiling của tôi khá tốt. Tuy nhiên, một trường hợp sử dụng cho tic-tocchức năng giống đã nảy sinh khi tôi cố gắng lập hồ sơ các phép tính được điều khiển tương tác, tức là bằng chuyển động chuột của người dùng trong GUI. Tôi cảm thấy như gửi thư rác tics và tocs trong các nguồn trong khi thử nghiệm tương tác sẽ là cách nhanh nhất để tiết lộ tắc nghẽn. Tôi đã tham gia Timerlớp học của Eli Bendersky , nhưng không hoàn toàn hài lòng, vì nó yêu cầu tôi thay đổi thụt đầu dòng trong mã của mình, điều này có thể gây bất tiện trong một số trình chỉnh sửa và gây nhầm lẫn cho hệ thống kiểm soát phiên bản. Hơn nữa, có thể cần phải đo thời gian giữa các điểm trong các chức năng khác nhau, điều này sẽ không hoạt động vớiwithtuyên bố. Sau khi thử rất nhiều sự thông minh của Python, đây là giải pháp đơn giản mà tôi thấy hiệu quả nhất:

from time import time
_tstart_stack = []

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

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

Vì điều này hoạt động bằng cách đẩy thời gian bắt đầu vào một ngăn xếp, nó sẽ hoạt động chính xác cho nhiều cấp độ tics và tocs. Nó cũng cho phép một người thay đổi chuỗi định dạng của toccâu lệnh để hiển thị thông tin bổ sung, mà tôi thích về Timerlớp của Eli .

Vì một số lý do, tôi quan tâm đến chi phí triển khai Python thuần túy, vì vậy tôi cũng đã thử nghiệm một mô-đun mở rộng C:

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

Đây là dành cho MacOSX và tôi đã bỏ qua mã để kiểm tra xem có lvlnằm ngoài giới hạn hay không cho ngắn gọn. Trong khi tictoc.res()mang lại độ phân giải khoảng 50 nano giây trên hệ thống của tôi, tôi nhận thấy rằng độ rung khi đo bất kỳ câu lệnh Python nào dễ dàng nằm trong phạm vi micro giây (và nhiều hơn nữa khi được sử dụng từ IPython). Tại thời điểm này, chi phí triển khai Python trở nên không đáng kể, vì vậy nó có thể được sử dụng với độ tin cậy tương tự như việc triển khai C.

Tôi nhận thấy rằng tính hữu ích của tic-toc-approach thực tế bị giới hạn ở các khối mã mất hơn 10 micro giây để thực thi. Dưới đó, các chiến lược tính trung bình như trong timeitđược yêu cầu để có được một phép đo trung thực.


1
Cực kỳ thanh lịch, @Stefan - không thể tin được điều này lại được đánh giá thấp đến vậy. Cảm ơn!
thclark

10

Bạn có thể sử dụng tictoctừ ttictoc. Cài đặt nó với

pip install ttictoc

Và chỉ cần nhập chúng vào tập lệnh của bạn như sau

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

8

Tôi vừa tạo một mô-đun [tictoc.py] để đạt được các tocs tic lồng nhau, đó là những gì Matlab làm.

from time import time

tics = []

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

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

Và nó hoạt động theo cách này:

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

Tôi hy vọng nó sẽ giúp.


Bản sao tốt của tic / toc từ MATLAB!
Matt,

1
Tôi phải cảnh báo bạn rằng điều này có thể không hoạt động như mong muốn khi được sử dụng đồng thời bởi nhiều hơn 1 mô-đun, vì các mô-đun (AFAIK) hoạt động giống như các đĩa đơn.
antonimmo

3

Hãy xem các timeitmô-đun. Nó không thực sự tương đương nhưng nếu mã bạn muốn đếm thời gian nằm trong một hàm, bạn có thể dễ dàng sử dụng nó.


Có, timeitlà tốt nhất cho điểm chuẩn. Nó thậm chí không cần phải là một hàm duy nhất, bạn có thể chuyển các câu lệnh phức tạp.

10
Chà, việc chuyển mã không phải là một lệnh gọi hàm cực kỳ đơn giản như một chuỗi là rất xấu.
ThiefMaster


1

Điều này cũng có thể được thực hiện bằng cách sử dụng một trình bao bọc. Cách giữ thời gian rất chung chung.

Trình bao bọc trong mã ví dụ này bao bọc bất kỳ hàm nào và in ra khoảng thời gian cần thiết để thực thi hàm:

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

Hàm wrapper, thời gian này được gọi là decorator. Giải thích chi tiết hơn một chút, tại đây: medium.com/pythonhive/…
Mircea

1

Tôi đã thay đổi câu trả lời của @Eli Bendersky một chút để sử dụng ctor __init__()và dtor __del__()để định thời gian, để có thể sử dụng nó thuận tiện hơn mà không cần thụt lề mã gốc:

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)

Để sử dụng, đơn giản đặt Timer ("blahblah") ở đầu một số phạm vi cục bộ. Thời gian đã trôi qua sẽ được in ở cuối phạm vi:

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

Nó in ra:

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
Một vấn đề với việc triển khai này là thực tế, nó timerkhông bị xóa sau lần gọi cuối cùng, nếu bất kỳ mã nào khác theo sau forvòng lặp. Để nhận giá trị bộ đếm thời gian cuối cùng, người ta nên xóa hoặc ghi đè lên timersau forvòng lặp, ví dụ qua timer = None.
khốn nạn,

1
@bastelflp Chỉ cần nhận ra rằng tôi đã hiểu sai ý của bạn ... Đề xuất của bạn hiện đã được kết hợp trong mã. Cảm ơn.
Shaohua Li,

1

Cập nhật câu trả lời của Eli cho 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)

Cũng giống như của Eli, nó có thể được sử dụng như một trình quản lý ngữ cảnh:

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

Đầu ra:

[Count] Elapsed: 0.27 seconds

Tôi cũng đã cập nhật nó để in đơn vị thời gian được báo cáo (giây) và cắt bớt số chữ số theo đề xuất của Can, và với tùy chọn thêm vào tệp nhật ký. Bạn phải nhập ngày giờ để sử dụng tính năng ghi nhật ký:

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

0

Dựa trên câu trả lời của Stefan và antonimmo, tôi đã kết thúc

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

trong một utils.pymô-đun và tôi sử dụng nó với

from utils import Tictoc
tic, toc = Tictoc()

Cách này

  • bạn chỉ có thể sử dụng tic(), toc()và làm tổ họ thích trong Matlab
  • Ngoài ra, bạn có thể đặt tên cho họ: tic(1), toc(1)hay tic('very-important-block'), toc('very-important-block')và giờ với tên gọi khác nhau sẽ không can thiệp
  • nhập chúng theo cách này ngăn cản sự can thiệp giữa các mô-đun sử dụng nó.

(ở đây toc không in thời gian đã trôi qua mà trả về nó.)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.