如何获取Python程序执行的时间?

1722

我有一个用Python编写的命令行程序,运行时间比较长。我想知道它完成运行所需的精确时间。

我查看了timeit模块,但是它似乎只适用于小片段的代码。我想计时整个程序的运行时间。


太棒了,谢谢你的问题!下面的各位给出了很好的答案。帮我节省了时间。 - Qazi Ammar
39个回答

30

对于使用Jupyter笔记本的数据人员

在单元格中,您可以使用Jupyter的%%time魔法命令来测量执行时间:

%%time
[ x**2 for x in range(10000)]

输出

CPU times: user 4.54 ms, sys: 0 ns, total: 4.54 ms
Wall time: 4.12 ms

这将仅捕获特定单元格的执行时间。如果您想捕获整个笔记本(即程序)的执行时间,可以在同一目录中创建一个新笔记本,在新笔记本中执行所有单元格:

假设上面的笔记本名为example_notebook.ipynb。在同一目录下的新笔记本中:
# Convert your notebook to a .py script:
!jupyter nbconvert --to script example_notebook.ipynb

# Run the example_notebook with -t flag for time
%run -t example_notebook

输出

IPython CPU timings (estimated):
  User   :       0.00 s.
  System :       0.00 s.
Wall time:       0.00 s.

21
以下代码片段以易读的<HH:MM:SS>格式打印经过的时间。
import time
from datetime import timedelta

start_time = time.time()

#
# Perform lots of computations.
#

elapsed_time_secs = time.time() - start_time

msg = "Execution took: %s secs (Wall clock time)" % timedelta(seconds=round(elapsed_time_secs))

print(msg)    

3
在这里最明智的答案是一直沿用内建功能,这样可以避免大量的输入,从而使答案更加简单易懂。 - ijoseph

21

与@rogeriopvl的回答类似,我稍作修改,使用同一库将时间转换为小时、分钟和秒钟,用于长时间运行的作业。

import time
start_time = time.time()
main()
seconds = time.time() - start_time
print('Time Taken:', time.strftime("%H:%M:%S",time.gmtime(seconds)))

样例输出

Time Taken: 00:00:08

正是我所需要的!谢谢! - Bernardo Troncoso

18

对于函数,我建议使用我创建的这个简单的装饰器。

def timeit(method):
    def timed(*args, **kwargs):
        ts = time.time()
        result = method(*args, **kwargs)
        te = time.time()
        if 'log_time' in kwargs:
            name = kwargs.get('log_name', method.__name__.upper())
            kwargs['log_time'][name] = int((te - ts) * 1000)
        else:
            print('%r  %2.22f ms' % (method.__name__, (te - ts) * 1000))
        return result
    return timed

@timeit
def foo():
    do_some_work()

# foo()
# 'foo'  0.000953 ms

  1. 如何在kwargs中使用"log_name"?
  2. 使用"get"是否有些冗余?我的意思是,如果'log_time'在kwargs中,那么kwargs.get('log_name',...)等同于kwargs['log_name'],不是吗?
- Yuval Zilber
过于复杂化,f字符串在哪里? - Yu Da Chi
我喜欢这种方法。 - Mykola

13
from time import time
start_time = time()
...
end_time = time()
time_taken = end_time - start_time # time_taken is in seconds
hours, rest = divmod(time_taken,3600)
minutes, seconds = divmod(rest, 60)

11

我已经查看了timeit模块,但它似乎只适用于小代码段。我想计时整个程序。

$ python -mtimeit -n1 -r1 -t -s "from your_module import main" "main()"

它运行your_module.main()函数一次,并使用time.time()函数作为计时器打印经过的时间。

要在Python中模拟/usr/bin/time功能,请参见Python subprocess with /usr/bin/time: how to capture timing info but ignore all other output?

要测量每个函数的CPU时间(例如,不包括time.sleep()期间的时间),可以使用profile模块(Python 2上的cProfile):

$ python3 -mprofile your_module.py

如果你想使用与profile模块相同的计时器,可以在上面的timeit命令中传入-p参数。

参见如何对Python脚本进行性能分析?


11

我在许多地方都遇到了同样的问题,因此我创建了一个方便的包horology。您可以使用pip install horology安装它,然后以优雅的方式执行:

from horology import Timing

with Timing(name='Important calculations: '):
    prepare()
    do_your_stuff()
    finish_sth()

将输出:

Important calculations: 12.43 ms

或者更简单的方法(如果您只有一个函数):

from horology import timed

@timed
def main():
    ...

将输出:

main: 7.12 h

它处理单位和舍入。它适用于Python 3.6或更新版本。


@DarrenZou 请在这里查看更多的文档和资源: https://github.com/mjmikulski/horology - hans
我可以将这些值存储在一个变量中吗? - Jaime02
是的,请使用 main.interval - hans
2
@hans,恭喜你开发出这个库——真是一个了不起的工具。 - ROBBAT1

10

我也喜欢Paul McGuire的回答,但我想出了一种适合我需求更多的上下文管理器形式。

import datetime as dt
import timeit

class TimingManager(object):
    """Context Manager used with the statement 'with' to time some execution.

    Example:

    with TimingManager() as t:
       # Code to time
    """

    clock = timeit.default_timer

    def __enter__(self):
        """
        """
        self.start = self.clock()
        self.log('\n=> Start Timing: {}')

        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """
        """
        self.endlog()

        return False

    def log(self, s, elapsed=None):
        """Log current time and elapsed time if present.
        :param s: Text to display, use '{}' to format the text with
            the current time.
        :param elapsed: Elapsed time to display. Dafault: None, no display.
        """
        print s.format(self._secondsToStr(self.clock()))

        if(elapsed is not None):
            print 'Elapsed time: {}\n'.format(elapsed)

    def endlog(self):
        """Log time for the end of execution with elapsed time.
        """
        self.log('=> End Timing: {}', self.now())

    def now(self):
        """Return current elapsed time as hh:mm:ss string.
        :return: String.
        """
        return str(dt.timedelta(seconds = self.clock() - self.start))

    def _secondsToStr(self, sec):
        """Convert timestamp to h:mm:ss string.
        :param sec: Timestamp.
        """
        return str(dt.datetime.fromtimestamp(sec))

10
我认为这是最好且最简单的方法:
from time import monotonic

start_time = monotonic()
# something
print(f"Run time {monotonic() - start_time} seconds")

或者使用装饰器:

from time import monotonic
    
def record_time(function):
    def wrap(*args, **kwargs):
        start_time = monotonic()
        function_return = function(*args, **kwargs)
        print(f"Run time {monotonic() - start_time} seconds")
        return function_return
    return wrap

@record_time
def your_function():
    # something

9
IPython 中,"timeit" 任何脚本:
def foo():
    %run bar.py
timeit foo()

如果您使用%%timeit(两个百分号),则可以像此相关答案所示一样节省定义函数foo的步骤。 - ojdo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接