Hàm đo thời gian trong Python


123

Tôi muốn tạo một hàm python để kiểm tra thời gian dành cho mỗi hàm và in tên của nó cùng với thời gian của nó, làm cách nào tôi có thể in tên hàm và nếu có cách nào khác để làm như vậy, vui lòng cho tôi biết

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

Các công cụ lập hồ sơ Python có thể hiển thị cho bạn tên hàm và thời gian dành cho từng hàm. Đọc ở đây: docs.python.org/library/profile.html
Roadmaster

Sử dụng tốt hơn timeitcho phép đo. Nó không hoàn hảo, nhưng nó đánh bại cú đâm của bạn từ xa và nó dễ sử dụng timeithơn nhiều so với việc tự mình làm ra thứ gì đó tốt hơn.

Câu trả lời:


241

Trước hết, tôi đánh giá cao đề nghị sử dụng một hồ sơ hoặc ít nhất sử dụng timeit .

Tuy nhiên, nếu bạn muốn viết phương pháp tính thời gian của riêng mình một cách chặt chẽ để học, thì đây là nơi để bắt đầu sử dụng trình trang trí.

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

Và cách sử dụng rất đơn giản, chỉ cần sử dụng trình trang trí @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

Lưu ý rằng tôi đang gọi f.func_nameđể lấy tên hàm dưới dạng chuỗi (trong Python 2) hoặc f.__name__ trong Python 3.


4
chính xác những gì tôi muốn :) ... nhưng cậu đã thuyết phục tôi để sử dụng profiler python
Wazery

3
Có vẻ như điều này giả định rằng time.time () báo cáo thời gian tính bằng micro giây kể từ kỷ nguyên? Tài liệu cho biết nó báo cáo thời gian tính bằng giây docs.python.org/2/library/time.html#time.time .
Rahul Jha

Điều này không thể có hiệu lực sau khi sử dụng năng suất trong func. Làm cách nào để tôi vẫn sử dụng phương pháp này và có thể sử dụng năng suất?
jiamo

def timing (f): def wrap (* args, ** kwargs): time1 = time.time () ret = f (* args, ** kwargs) time2 = time.time () print '% s hàm lấy% 0.3 f ms'% (f.func_name, (time2-time1) * 1000) return ret quấn trở lại
Vivek Bagaria

1
có gì bất lợi khi tự viết nó? Việc lưu trữ danh sách thời gian đã trôi qua và kiểm tra phân phối của chúng có đủ đơn giản không?
3pitt

51

Sau khi chơi với timeitmô-đun, tôi không thích giao diện của nó, nó không được trang nhã so với hai phương pháp sau.

Đoạn mã sau bằng Python 3.

Phương pháp trang trí

Điều này gần giống với phương pháp của @ Mike. Ở đây tôi thêm kwargsfunctoolsquấn để làm cho nó tốt hơ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)

Phương pháp quản lý ngữ cảnh

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

Ví dụ, bạn có thể sử dụng nó như:

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

Và mã trong withkhối sẽ được tính giờ.

Phần kết luận

Sử dụng phương pháp đầu tiên, bạn có thể bình luận của người trang trí để lấy mã bình thường. Tuy nhiên, nó chỉ có thể định thời gian cho một hàm. Nếu bạn có một số phần mã mà bạn không biết làm cho nó trở thành một hàm, thì bạn có thể chọn phương pháp thứ hai.

Ví dụ, bây giờ bạn có

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

Bây giờ bạn muốn thời gian bigImage = ...dòng. Nếu bạn thay đổi nó thành một hàm, nó sẽ là:

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

Có vẻ không quá tuyệt vời ... Điều gì sẽ xảy ra nếu bạn đang sử dụng Python 2, không có nonlocaltừ khóa.

Thay vào đó, sử dụng phương pháp thứ hai rất phù hợp ở đây:

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

Đóng góp thú vị, tuy nhiên tôi thấy thật vô ích khi trong phương pháp decorator mà bạn đã đề cập, bạn phải thay đổi timeitgiao diện và sử dụng wraps()chức năng của functoolsmô-đun. Ý tôi là tất cả mã bổ sung đó là không cần thiết.
Billal Begueradj

1
Nhu cầuimport functools
Guillaume Chevalier

1
Lưu ý rằng trang trí của bạn thua giá trị trả về của hàm gốc
Marc Van Daele

11

Tôi không hiểu vấn đề với timeitmô-đun là gì. Đây có lẽ là cách đơn giản nhất để làm điều đó.

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

Nó cũng có thể gửi các đối số đến các hàm. Tất cả những gì bạn cần là hoàn thiện chức năng của mình bằng cách sử dụng trình trang trí. Giải thích thêm tại đây: http://www.pythoncentral.io/time-a-python- Chức năng/

Trường hợp duy nhất mà bạn có thể quan tâm đến việc viết các câu lệnh thời gian của riêng mình là nếu bạn muốn chạy một hàm chỉ một lần và cũng muốn nhận giá trị trả về của nó.

Lợi thế của việc sử dụng timeitmô-đun là nó cho phép bạn lặp lại số lần thực thi. Điều này có thể cần thiết vì các quy trình khác có thể ảnh hưởng đến độ chính xác về thời gian của bạn. Vì vậy, bạn nên chạy nó nhiều lần và xem giá trị thấp nhất.


3
Gửi đối số đến hàm bằng trình bao bọc và trình trang trí? Tại sao không timeit.timeit(lambda: func(a,b,c), number=1)? Tôi sử dụng điều này khi thực hiện các bài kiểm tra về một giải pháp giả định trong một thiết bị đầu cuối.
Jack

11

Timeit có hai lỗi lớn: nó không trả về giá trị trả về của hàm và nó sử dụng eval, yêu cầu chuyển thêm mã thiết lập để nhập. Điều này giải quyết cả hai vấn đề một cách đơn giản và thanh lịch:

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)

Cảm ơn! timeit không hoạt động tốt với Apache Spark vì bạn phải nhập tất cả các phụ thuộc Spark và ai muốn tạo một chuỗi cũ lớn thực hiện điều đó? Giải pháp này đơn giản và linh hoạt hơn nhiều.
Paul

4

Có một công cụ dễ dàng để tính thời gian. https://github.com/RalphMao/PyTimer

Nó có thể hoạt động giống như một người trang trí :

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

Đầu ra:

matmul:0.368434
matmul:2.839355

Nó cũng có thể hoạt động giống như một bộ đếm thời gian plug-in có kiểm soát vùng tên (hữu ích nếu bạn đang chèn nó vào một hàm có nhiều mã và có thể được gọi ở bất kỳ nơi nào khác).

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

Đầu ra:

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

Hy vọng nó sẽ giúp ích


3

Phương pháp trang trí bằng cách sử dụng thư viện Python trang trí:

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

Xem bài đăng trên Blog của tôi:

đăng trên Blog mobilepro.pl

bài đăng của tôi trên Google Plus


1

Cách làm của tôi:

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

Đặt một biến như start = time()trước khi thực thi hàm / vòng và printTime(start)ngay sau khối.

và bạn đã có câu trả lời.

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.