ChatGPT解决这个技术问题 Extra ChatGPT

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

我有一个 Python 命令行程序,需要一段时间才能完成。我想知道完成跑步所需的确切时间。

我查看了 timeit 模块,但它似乎只适用于一小段代码。我想为整个节目计时。


P
Peter Mortensen

Python中最简单的方法:

import time
start_time = time.time()
main()
print("--- %s seconds ---" % (time.time() - start_time))

这假设您的程序至少需要十分之一秒才能运行。

印刷:

--- 0.764891862869 seconds ---

这会计算实时时间(包括其他程序使用的时间),因此当您的计算机忙于做其他事情时,它似乎需要更多时间
在 Windows 上,做同样的事情,但使用 time.clock() 而不是 time.time()。你会得到更好的准确性。
我建议做 round(time.time() - start_time, 2)(或任何你想要的小数),我得到了像 1.24e-5 这样的科学数字。
@ThorSummoner:你可能想要 '%.2f' 而不是 round() 这里。
这种方法有一个很大的缺陷。如果在程序运行时系统时间发生变化(例如与时间服务器同步),那么此方法将不起作用,甚至可能会破坏代码(负持续时间......)
C
Community

我将此 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 形式。)

注意:可以在 herehere 中找到上述代码的 Python 3 版本。


这是一个真正干净的解决方案,如果您按 Ctrl-C 停止程序,它也可以工作。
很棒的解决方案我一定会使用它并创建一个时序装饰器来识别瓶颈功能
对于 Python 3,在顶部添加 from functools import reduce 并在每个打印语句周围加上括号。效果很好!
@PowerApp101 - 谢谢 - Nicojo 的回答提供了这个模块的 Py3 友好版本。
注意:time.clock() 是“自 3.3 版以来已弃用:此函数的行为取决于平台:根据您的要求,使用 perf_counter() [有时间睡眠] 或 process_time() [没有时间睡眠]有明确的行为。”
v
vipulgupta2048

在 Linux 或 Unix 中:

$ time python yourprogram.py

在 Windows 中,请参阅以下 StackOverflow 问题:How do I measure execution time of a command on the Windows command line?

要获得更详细的输出,

$ 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 应用程序中,我们如何计算该小部件显示所需的时间?
但这似乎并没有以分钟为单位给出时间:秒它最终是一个浮点数!
是的,它给出了几秒钟。如果需要,您可以转换为 min:seconds。查看 Paul McGuire 的答案及其 secondsToStr() 函数。
这也适用于 MacO。
P
Peter Mortensen

我喜欢 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

正如 JF Sebastian 所提到的,这种方法可能会遇到一些本地时间的棘手情况,因此使用起来更安全:

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

@phansen:您可以在此处使用 timedelta(seconds=time.monotonic()-start)(如果间隔很大,则可以使用 time.time())。 Don't subtract naive datetime objects that represent local time; local time is not monotonous
好的,你的意思是像 start_time = time.monotonic(); end_time = time.monotonic(); timedelta(seconds=end_time - start_time)。我相信您是对的,但是当您返回 datetime.timedelta(0, 0, 76) 时,您还必须对其进行格式化。此外,似乎单调方法仅在 Python 3 中添加。
喔好吧。我看到您可以将其传递给 str() 以使其成为“人类”。我会更新答案,谢谢。
S
Shidouuu
import time

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

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


time.time() 最好在 *nix 上使用。 time.clock() 最好在 Windows 上使用。
我相信这不能用于计算“仅此进程使用的时间”,因为它使用系统时间并且会受到其他系统进程的影响?如果我错了,请纠正我:)
注意:time.clock() 是“自 3.3 版以来已弃用:此函数的行为取决于平台:根据您的要求,使用 perf_counter() [有时间睡眠] 或 process_time() [没有时间睡眠]有明确的行为。”
G
Georgy

我真的很喜欢 Paul McGuire's answer,但我使用 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")

如果你觉得这很有用,你仍然应该投票给他的答案而不是这个答案,因为他做了大部分工作;)。


我发现 timedelta(seconds=t).total_seconds() 很有帮助。
你能解释一下这些函数的作用吗? log 命令中的 s 是什么?什么是atexit?
@SumNeuron,简而言之,这些函数会打印出您使用它的程序的执行时间。 s 是 log 的第一个参数,应该是一个字符串。 log 是一个打印时间信息的函数。 atexit 是一个 python 模块,可让您注册要在程序退出时调用的函数。
@Nicojo 非常有帮助。我有一个关于如何使用此代码来测试例如循环执行时间的问题。假设我有一个包含循环的函数,我想得到这个循环所花费的时间
@moudi 这个问题的最佳答案是你最好的选择。只需在循环之前设置开始时间,并在循环退出时计算经过的时间。
P
Peter Mortensen

您可以使用 Python 分析器 cProfile 来测量 CPU time 以及在每个函数中花费的时间以及每个函数被调用的次数。如果您想在不知道从哪里开始的情况下提高脚本的性能,这将非常有用。 This answer 到另一个 Stack Overflow 问题非常好。看看 the documentation 总是好的。

以下是如何从命令行使用 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 第一行是 X function calls in Y CPU seconds。如果您想要挂钟时间,请在此处使用其他答案之一。
d
djamaile

只需使用 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

它会在几秒钟内返回,您可以获得执行时间。这很简单,但是您应该将这些写在启动程序执行的 w main 函数中。如果即使遇到错误也想获得执行时间,那么将参数“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))

不应该是 finally 部分下的那个部分吗?
Y
Yas

时间.时钟()

3.3 版后已弃用:此函数的行为取决于平台:根据您的要求使用 perf_counter() 或 process_time() 来获得明确定义的行为。

time.perf_counter()

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

time.process_time()

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

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

也许从结论开始,“使用 time.process_time()”(或类似的)?
P
Peter Mortensen

对于使用 Jupyter Notebook 的数据人员

在单元格中,您可以使用 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.

S
Suraj Rao

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

这应该是公认的答案。 Perf 计数器测量实际进程的性能,而不仅仅是自启动以来经过的时间,也可能受到其他进程的影响。
S
Sandeep

以下代码段以易于阅读的 <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)    

一直到这里,人们找到了最理智的答案(“理智”的意思是尽可能多地依赖内置插件,因此打字最少)。
u
user 923227

与@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

正是我想要的!谢谢!
N
Nikita Tonkoskur

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

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'],不是吗?
过于复杂,f 字符串在哪里? ..
我喜欢这种方法
T
The6thSense
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)

j
jfs

我查看了 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 模块相同的计时器,您可以将 -p 传递给上面的 timeit 命令。

请参阅How can you profile a Python script?


h
hans

我在很多地方都遇到了同样的问题,所以我创建了一个便利包 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 查看更多文档和资源here
我可以在变量中获取该值吗?
是的,使用 main.interval
@hans,恭喜这个库 - 很棒的工具。
P
Peter Mortensen

我也喜欢 Paul McGuire's answer,并想出了一个更适合我需要的上下文管理器表单。

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

P
Peter Mortensen

IPython 中,“timeit”任何脚本:

def foo():
    %run bar.py
timeit foo()

如果您使用 %%timeit(百分之二),您可以保存定义函数 foo,如 this related answer 所示。
P
Peter Mortensen

我使用了一个非常简单的函数来计时部分代码执行:

import time
def timing():
    start_time = time.time()
    return lambda x: print("[{:.2f}s] {}".format(time.time() - start_time, x))

要使用它,只需在要测量的代码之前调用它以检索函数时序,然后在代码之后调用带有注释的函数。时间会出现在评论前面。例如:

t = timing()
train = pd.read_csv('train.csv',
                        dtype={
                            'id': str,
                            'vendor_id': str,
                            'pickup_datetime': str,
                            'dropoff_datetime': str,
                            'passenger_count': int,
                            'pickup_longitude': np.float64,
                            'pickup_latitude': np.float64,
                            'dropoff_longitude': np.float64,
                            'dropoff_latitude': np.float64,
                            'store_and_fwd_flag': str,
                            'trip_duration': int,
                        },
                        parse_dates = ['pickup_datetime', 'dropoff_datetime'],
                   )
t("Loaded {} rows data from 'train'".format(len(train)))

然后输出将如下所示:

[9.35s] Loaded 1458644 rows data from 'train'

H
Hafez Ahmad

我尝试使用以下脚本找到时差。

import time

start_time = time.perf_counter()
[main code here]
print (time.perf_counter() - start_time, "seconds")

time.perf_counter(): float - 返回性能计数器的值(以秒为单位),即具有最高可用分辨率的时钟以测量短持续时间。它确实包括睡眠期间经过的时间,并且是系统范围的。返回值的参考点是未定义的,因此只有连续调用的结果之间的差异才有效。 docs.python.org/3/library/time.html#time.perf_counter
P
Peter Mortensen

使用 line_profiler

line_profiler 将分析各行代码执行所需的时间。探查器通过 Cython 在 C 中实现,以减少探查的开销。

from line_profiler import LineProfiler
import random

def do_stuff(numbers):
    s = sum(numbers)
    l = [numbers[i]/43 for i in range(len(numbers))]
    m = ['hello'+str(numbers[i]) for i in range(len(numbers))]

numbers = [random.randint(1,100) for i in range(1000)]
lp = LineProfiler()
lp_wrapper = lp(do_stuff)
lp_wrapper(numbers)
lp.print_stats()

结果将是:

Timer unit: 1e-06 s

Total time: 0.000649 s
File: <ipython-input-2-2e060b054fea>
Function: do_stuff at line 4

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     4                                           def do_stuff(numbers):
     5         1           10     10.0      1.5      s = sum(numbers)
     6         1          186    186.0     28.7      l = [numbers[i]/43 for i in range(len(numbers))]
     7         1          453    453.0     69.8      m = ['hello'+str(numbers[i]) for i in range(len(numbers))]

很好的例子。很好地满足我的需求。感谢你的分享。
P
Peter Mortensen

Timeit 是 Python 中的一个类,用于计算小块代码的执行时间。

Default_timer 是此类中的一个方法,用于测量挂钟时间,而不是 CPU 执行时间。因此,其他进程执行可能会干扰这一点。因此,它对于小代码块很有用。

代码示例如下:

from timeit import default_timer as timer

start= timer()

# Some logic

end = timer()

print("Time taken:", end-start)

G
Georgy

首先,通过以管理员身份打开命令提示符 (CMD) 来安装 humanfriendly 包,然后在此处键入 - pip install humanfriendly

代码:

from humanfriendly import format_timespan
import time
begin_time = time.time()
# Put your code here
end_time = time.time() - begin_time
print("Total execution time: ", format_timespan(end_time))

输出:

https://i.stack.imgur.com/VPJNE.png


s
swateek

您只需在 Python 中执行此操作。没有必要让它变得复杂。

import time

start = time.localtime()
end = time.localtime()
"""Total execution time in minutes$ """
print(end.tm_min - start.tm_min)
"""Total execution time in seconds$ """
print(end.tm_sec - start.tm_sec)

好吧,如果执行运行到几分钟......这个解决方案无法解决这个问题。
P
Pedro Lobito

稍后回答,但我使用内置 timeit

import timeit
code_to_test = """
a = range(100000)
b = []
for i in a:
    b.append(i*2)
"""
elapsed_time = timeit.timeit(code_to_test, number=500)
print(elapsed_time)
# 10.159821493085474

在 code_to_test 中包装所有代码,包括您可能拥有的任何导入。

number 参数指定代码应该重复的次数。

演示


如果您想对不能放入字符串的代码部分进行计时怎么办?
@daniel您可以创建一个新问题。如果您在此处发布链接,我可能会为您提供帮助。
是的,我讨厌在字符串中运行代码只是为了满足 timeit()
P
Peter Mortensen

有一个 timeit 模块可用于对 Python 代码的执行时间进行计时。

它在 Python 文档 26.6. timeit — Measure execution time of small code snippets 中有详细的文档和示例。


OP 在问题中明确提到了 timeit。问题是如何在这里使用它(或者应该在这里使用它以及有哪些替代方案)。这是possible answer
N
Nick Legend

以下 this answer 创建了一个简单但方便的工具。

import time
from datetime import timedelta

def start_time_measure(message=None):
    if message:
        print(message)
    return time.monotonic()

def end_time_measure(start_time, print_prefix=None):
    end_time = time.monotonic()
    if print_prefix:
        print(print_prefix + str(timedelta(seconds=end_time - start_time)))
    return end_time

用法:

total_start_time = start_time_measure()    
start_time = start_time_measure('Doing something...')
# Do something
end_time_measure(start_time, 'Done in: ')
start_time = start_time_measure('Doing something else...')
# Do something else
end_time_measure(start_time, 'Done in: ')
end_time_measure(total_start_time, 'Total time: ')

输出:

Doing something...
Done in: 0:00:01.218000
Doing something else...
Done in: 0:00:01.313000
Total time: 0:00:02.672000

P
Peter Mortensen

这是对我有用的 Paul McGuire's answer。以防万一有人在运行该程序时遇到问题。

import atexit
from time import clock

def reduce(function, iterable, initializer=None):
    it = iter(iterable)
    if initializer is None:
        value = next(it)
    else:
        value = initializer
    for element in it:
        value = function(value, element)
    return value

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)

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

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

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

导入文件后,从您的程序中调用 timing.main()


P
Peter Mortensen

Python 程序执行度量的时间可能不一致,具体取决于:

可以使用不同的算法评估相同的程序

运行时间因算法而异

运行时间因实现而异

运行时间因计算机而异

运行时间无法根据小输入来预测

这是因为最有效的方法是使用“增长顺序”并学习 Big "O" notation 以正确执行此操作。

无论如何,您可以尝试使用这个简单的算法来评估任何 Python 程序在每秒特定机器计数步骤中的性能:将其调整为您要评估的程序

import time

now = time.time()
future = now + 10
step = 4 # Why 4 steps? Because until here already four operations executed
while time.time() < future:
    step += 3 # Why 3 again? Because a while loop executes one comparison and one plus equal statement
step += 4 # Why 3 more? Because one comparison starting while when time is over plus the final assignment of step + 1 and print statement
print(str(int(step / 10)) + " steps per second")