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

1722

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

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


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

2943

在Python中最简单的方法:

import time
start_time = time.time()
main()
print("--- %s seconds ---" % (time.time() - start_time))
这个假设是你的程序至少需要运行十分之一秒。
打印:
--- 0.764891862869 seconds ---

113
这会计算真实时间(包括其他程序占用的时间),因此当你的电脑正在忙于处理其他任务时,它看起来需要更长的时间。 - newacct
67
在Windows上,做同样的事情,但使用time.clock()代替time.time()。这样可以获得稍微更好的准确性。 - Corey Goldberg
70
我建议使用 round(time.time() - start_time, 2)(或者你想要的任何小数位数),因为我得到的科学计数法数字像是1.24e-5。 - ThorSummoner
48
@ThorSummoner: 在这里,你可能想要使用'%.2f'而不是round() - jfs
26
这种方法有一个很大的缺陷。如果程序在运行时系统时间发生变化(比如与时间服务器同步),那么这种方法就无法工作,甚至可能会破坏代码(出现负时间间隔等问题)。 - Gilad
显示剩余9条评论

288

在 Linux 或 Unix 系统中:

$ time python yourprogram.py

在Windows中,请参考此StackOverflow问题:如何在Windows命令行中测量命令的执行时间?

如果需要更详细的输出,

$ time -v python yourprogram.py
    Command being timed: "python3 yourprogram.py"
    User time (seconds): 0.08
    System time (seconds): 0.02
    Percent of CPU this job got: 98%
    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.10
    Average shared text size (kbytes): 0
    Average unshared data size (kbytes): 0
    Average stack size (kbytes): 0
    Average total size (kbytes): 0
    Maximum resident set size (kbytes): 9480
    Average resident set size (kbytes): 0
    Major (requiring I/O) page faults: 0
    Minor (reclaiming a frame) page faults: 1114
    Voluntary context switches: 0
    Involuntary context switches: 22
    Swaps: 0
    File system inputs: 0
    File system outputs: 0
    Socket messages sent: 0
    Socket messages received: 0
    Signals delivered: 0
    Page size (bytes): 4096
    Exit status: 0

如果我要启动另一个小部件,例如在QT应用程序中,我们如何计算该小部件显示所需的时间? - Ciasto piekarz
但是这似乎没有给出以分钟:秒为单位的时间,而是得到了一个浮点数!! - Ciasto piekarz
3
可以得到一个秒数。如果需要,您可以将其转换为分钟:秒。请参阅保罗·麦克奎尔(Paul McGuire)的答案及其 secondsToStr() 函数。 - steveha
这也适用于MacOS。 - lapin

259

我将这个 timing.py 模块放入了我自己的 site-packages 目录中,并且只需在我的模块顶部插入 import timing

import atexit
from time import clock

def secondsToStr(t):
    return "%d:%02d:%02d.%03d" % \
        reduce(lambda ll,b : divmod(ll[0],b) + ll[1:],
            [(t*1000,),1000,60,60])

line = "="*40
def log(s, elapsed=None):
    print line
    print secondsToStr(clock()), '-', s
    if elapsed:
        print "Elapsed time:", elapsed
    print line
    print

def endlog():
    end = clock()
    elapsed = end-start
    log("End Program", secondsToStr(elapsed))

def now():
    return secondsToStr(clock())

start = clock()
atexit.register(endlog)
log("Start Program")

我还可以在程序中调用timing.log,以展示程序中的重要阶段。但是只需包含import timing就会打印开始和结束时间以及总共经过的时间。(请原谅我的模糊的secondsToStr函数,它只是将浮点数秒格式化为hh:mm:ss.sss形式。)
注意:上述代码的Python 3版本可以在这里这里找到。

11
这是一个真正干净的解决方案,即使你按Ctrl-C停止程序也能起作用。 - sorin
很棒的解决方案,我一定会使用它并创建一个计时装饰器来识别瓶颈函数。 - c24b
14
对于 Python 3,请在顶部添加 from functools import reduce,并在每个 print 语句周围加上括号。效果很好! - PowerApp101
3
@PowerApp101 - 感谢 - Nicojo的答案提供了此模块的适用于Py3的版本。 - PaulMcG
12
注意:time.clock()自版本3.3起已被弃用:该函数的行为取决于平台,请根据您的要求使用perf_counter() [包括睡眠时间]或process_time() [不包括睡眠时间]代替,以获得明确定义的行为。 - mab
显示剩余2条评论

151

我喜欢datetime模块提供的输出,其中时间增量对象以人类可读的方式显示天数,小时数,分钟数等。

例如:

from datetime import datetime
start_time = datetime.now()
# do your work here
end_time = datetime.now()
print('Duration: {}'.format(end_time - start_time))

示例输出例如:

Duration: 0:00:08.309267


Duration: 1 day, 1:51:24.269711

正如J.F. Sebastian所提到的那样,这种方法在处理本地时间时可能会遇到一些棘手的情况,因此更安全的做法是使用:

import time
from datetime import timedelta
start_time = time.monotonic()
end_time = time.monotonic()
print(timedelta(seconds=end_time - start_time))

2
@phansen:你可以在这里使用timedelta(seconds=time.monotonic()-start)(如果时间间隔很长,则可以使用time.time())。不要减去代表本地时间的naive datetime对象;本地时间不是单调的 - jfs
好的,你的意思是像这样 start_time = time.monotonic(); end_time = time.monotonic(); timedelta(seconds=end_time - start_time)。我相信你是对的,但是你还需要格式化它,因为你会得到 datetime.timedelta(0, 0, 76) 的返回值。另外,似乎 monotonic 方法只在 Python 3 中添加了。 - metakermit
啊,好的。我明白了,你可以将它传递给 str() 使其“人性化”。我会更新答案的,谢谢。 - metakermit

123
import time

start_time = time.clock()
main()
print(time.clock() - start_time, "seconds")

time.clock() 返回处理器时间,这使我们可以仅计算此进程使用的时间(在Unix上)。文档说:“无论如何,这是用于基准测试Python或计时算法的函数”。


18
time.time() 最好在 *nix 系统上使用。time.clock() 最好在 Windows 系统上使用。 - Corey Goldberg
我认为这不能用来计算“仅此进程使用的时间”,因为它使用系统时间并会受到其他系统进程的影响?如果我对此有误,请纠正我 :) - AnnanFay
25
注意:time.clock()已经“自版本3.3起弃用:此函数的行为取决于平台:根据您的需求使用带有睡眠时间的perf_counter()或不带睡眠时间的process_time()来代替,以获得明确定义的行为。” - mab

86

我非常喜欢Paul McGuire的答案,但我使用Python 3。所以对于那些感兴趣的人:这是他答案的一个修改版本,在*nix上可以与Python 3一起使用(我想,在Windows下应该使用clock()而不是time()):

#python3
import atexit
from time import time, strftime, localtime
from datetime import timedelta

def secondsToStr(elapsed=None):
    if elapsed is None:
        return strftime("%Y-%m-%d %H:%M:%S", localtime())
    else:
        return str(timedelta(seconds=elapsed))

def log(s, elapsed=None):
    line = "="*40
    print(line)
    print(secondsToStr(), '-', s)
    if elapsed:
        print("Elapsed time:", elapsed)
    print(line)
    print()

def endlog():
    end = time()
    elapsed = end-start
    log("End Program", secondsToStr(elapsed))

start = time()
atexit.register(endlog)
log("Start Program")

如果您发现这很有用,您仍应该点赞他的答案而不是这个答案,因为他做了大部分的工作;)。


1
我发现 timedelta(seconds=t).total_seconds() 很有用。 - nu everest
你能解释一下这些函数的作用吗?log命令中的s是什么?atexit是什么? - SumNeuron
@SumNeuron,简而言之,这些函数会打印出您使用它们的程序的执行时间。s是log的第一个参数,应该是一个字符串。log是一个打印时间信息的函数。atexit是一个Python模块,允许您注册在程序退出时调用的函数。 - Nicojo
@moudi 这个问题的最佳答案是你最好的选择。只需在循环之前设置开始时间,并在循环结束时计算经过的时间即可。 - Nicojo
我可以用它来计时较大模块中的代码部分吗?我已经尝试过了,似乎只有在“主函数”停止执行后才会停止计时。 - ruslaniv
显示剩余2条评论

82

您可以使用Python分析器cProfile来测量CPU时间,并且还可以了解每个函数内部花费的时间以及每个函数被调用的次数。如果您想要提高脚本的性能而不知道从哪里开始,这非常有用。这个答案是另一个Stack Overflow问题的很好的答案。查看文档也总是一个好习惯。

以下是使用cProfile从命令行对脚本进行分析的示例:

$ python -m cProfile euler048.py

1007 function calls in 0.061 CPU seconds

Ordered by: standard name
ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    1    0.000    0.000    0.061    0.061 <string>:1(<module>)
 1000    0.051    0.000    0.051    0.000 euler048.py:2(<lambda>)
    1    0.005    0.005    0.061    0.061 euler048.py:2(<module>)
    1    0.000    0.000    0.061    0.061 {execfile}
    1    0.002    0.002    0.053    0.053 {map}
    1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler objects}
    1    0.000    0.000    0.000    0.000 {range}
    1    0.003    0.003    0.003    0.003 {sum}

@jacwah 怎么计算总时间? - Chuck
@Chuck,第一行显示“在Y个CPU秒内调用X函数”。如果您想要墙上时间,请使用这里的其他答案之一。 - jacwah
@Chuck,你还可以使用“-s cumtime”按cumtime排序,这样你就可以在分析器的输出顶部找到答案了。 - tommy.carstensen

59

只需使用timeit模块。它可以在Python 2和Python 3中使用。

import timeit

start = timeit.default_timer()

# All the program statements
stop = timeit.default_timer()
execution_time = stop - start

print("Program Executed in "+str(execution_time)) # It returns time in seconds

它在几秒钟内返回并且您可以获得执行时间。虽然它很简单,但您应该将这些代码写在开始程序执行的主函数中。如果您想在发生错误时仍能获取执行时间,则需要将参数“Start”传递给它,并在那里计算,例如:

def sample_function(start,**kwargs):
     try:
         # Your statements
     except:
         # except statements run when your statements raise an exception
         stop = timeit.default_timer()
         execution_time = stop - start
         print("Program executed in " + str(execution_time))

6
那部分不应该放在“finally”部分吗? - alper

49

time.clock 已在Python 3.3中弃用,并将在Python 3.8中被移除: 使用time.perf_countertime.process_time代替

import time
start_time = time.perf_counter ()
for x in range(1, 100):
    print(x)
end_time = time.perf_counter ()
print(end_time - start_time, "seconds")

这个答案应该更靠前。 - Bouncner

43

time.clock()

自Python 3.3版本起已弃用:此函数行为因平台而异。请根据您的需求使用perf_counter()process_time(),以获得定义良好的行为。

time.perf_counter()

返回性能计数器的值(以分数秒为单位),即具有最高可用分辨率以测量短持续时间的时钟。它包括睡眠期间经过的时间,并且是系统范围内的。

time.process_time()

返回当前进程的系统和用户CPU时间总和的值(以分数秒为单位)。它不包括睡眠期间经过的时间。

start = time.process_time()
... do something
elapsed = (time.process_time() - start)

6
也许可以从结论开始,使用"time.process_time()"(或类似的函数)? - Peter Mortensen

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