使用“时间”模块测量经过时间


337

使用python中的时间模块,可以测量经过的时间吗?如果是这样,我该怎么做?

我需要这样做,以便如果光标在小部件中已存在一定时间,则会发生事件。


3
注意,使用的任何答案time.time()都不正确。最简单的示例是在测量期间是否更改了系统时间。
OrangeDog

我认为,关于您的原始问题,即如果光标在窗口小部件上停留一定时间会触发事件,我想docs.python.org/3/library/threading.html满足您的所有需求。多线程和带超时的条件变量可能是解决方案之一。但是,您目前的情况尚不清楚。
Tora

2
没有理由应该使用任何人time.time()来测量现代python中的经过时间(受手动更改,漂移,leap秒等影响)。考虑到这个问题现在是Google衡量经过时间的最佳结果,因此下面的答案应该更高。
NPras


1
@NPras忘记了“现代python”。使用它总是不正确的time.time()
OrangeDog

Answers:


514
start_time = time.time()
# your code
elapsed_time = time.time() - start_time

您还可以编写简单的装饰器来简化各种功能的执行时间的度量:

import time
from functools import wraps

PROF_DATA = {}

def profile(fn):
    @wraps(fn)
    def with_profiling(*args, **kwargs):
        start_time = time.time()

        ret = fn(*args, **kwargs)

        elapsed_time = time.time() - start_time

        if fn.__name__ not in PROF_DATA:
            PROF_DATA[fn.__name__] = [0, []]
        PROF_DATA[fn.__name__][0] += 1
        PROF_DATA[fn.__name__][1].append(elapsed_time)

        return ret

    return with_profiling

def print_prof_data():
    for fname, data in PROF_DATA.items():
        max_time = max(data[1])
        avg_time = sum(data[1]) / len(data[1])
        print "Function %s called %d times. " % (fname, data[0]),
        print 'Execution time max: %.3f, average: %.3f' % (max_time, avg_time)

def clear_prof_data():
    global PROF_DATA
    PROF_DATA = {}

用法:

@profile
def your_function(...):
    ...

您可以同时分析多个功能。然后要打印测量值,只需调用print_prof_data():


11
您还可以看看profilehooks pip install profilehooks,它在这里的主页
pjama

11
请注意,从Python 3.3开始,在测量超时或持续时间时可能应该使用time.monotonic()而不是time.time()docs.python.org/3/library/time.html#time.monotonic
Debilski 2015年

39
在此值得补充/注意的是,经过时间的度量单位为秒。
埃里克·克雷默

4
@EricKramer谢谢!我的巨大宠物,解释了测量方法而未定义测量单位。作为一个.NET的人第一次把脚趾浸入Python中,我自动想到了“毫秒”。
亚当·普洛彻

2
如果(例如)系统时钟被更改,并且可能没有亚秒分辨率,则无法使用。正确答案:stackoverflow.com/a/47637891/476716
OrangeDog

97

time.time() 会做的工作。

import time

start = time.time()
# run your code
end = time.time()

elapsed = end - start

您可能想看一下这个问题,但是我认为没有必要。


6
是的,时间以秒为单位
Eric Kramer

您应该将start更改为start_time。
Zoran Pandovski

time.time()这是一个坏主意,因为可以重置系统时钟,这会使您回到过去。time.monotonic()照顾到这一点(单调=仅向前)。time.perf_counter()也是单调的,但精度更高,因此建议将其用于挂钟时间。
xjcl

75

对于想要更好格式的用户,

import time
start_time = time.time()
# your script
elapsed_time = time.time() - start_time
time.strftime("%H:%M:%S", time.gmtime(elapsed_time))

将打印出2秒钟:

'00:00:02'

一秒钟持续7分钟:

'00:07:01'

请注意,使用gmtime的最小时间单位是秒。如果需要微秒,请考虑以下事项:

import datetime
start = datetime.datetime.now()
# some code
end = datetime.datetime.now()
elapsed = end - start
print(elapsed)
# or
print(elapsed.seconds,":",elapsed.microseconds) 

strftime 文档


1
谢谢您的回答,这启发了我。我将使用e = time.time() - start_time ; print("%02d:%02d:%02d" % (e // 3600, (e % 3600 // 60), (e % 60 // 1)))该收率几乎相同,以及覆盖超过24小时的情况。
Tora

@Tora您可能想签出“ {}”。format()而不是%02d来解决将来的兼容性问题。
罗格·霍夫斯特

2
谢谢!现在我已经习惯了新的。'{:02d}:{:02d}:{:02d}'。format(e // 3600,(e%3600 // 60),e%60)
Tora

可以time.monotonic()像其他答案一样使用吗?
endolith

elapsed.seconds如果持续时间大于一天,则将是错误的。您想elapsed.total_seconds()恢复活力
Ash Berlin-Taylor

51

为了获得最佳的经过时间度量(自Python 3.3起),请使用time.perf_counter()

返回性能计数器的值(以小数秒为单位),即具有最高可用分辨率的时钟以测量较短的持续时间。它确实包括整个系统的睡眠时间。返回值的参考点是不确定的,因此仅连续调用结果之间的差有效。

对于小时/天量级的测量,您不必担心亚秒级分辨率,请time.monotonic()改用。

返回单调时钟的值(以小数秒为单位),即不能向后移动的时钟。时钟不受系统时钟更新的影响。返回值的参考点是不确定的,因此仅连续调用结果之间的差有效。

在许多实现中,这些实际上可能是同一件事。

在3.3之前,您会受困于time.clock()

在Unix上,以秒为单位返回当前处理器时间,以浮点数表示。精度,实际上是“处理器时间”含义的确切定义,取决于同名C函数的精度。

在Windows上,此函数将基于Win32函数QueryPerformanceCounter()返回自第一次调用此函数以来经过的时间(以秒为单位)的浮点数。分辨率通常优于一微秒。


Python 3.7更新

PEP 564是Python 3.7中的新功能-添加具有纳秒分辨率的新时间函数。

使用这些可以进一步消除舍入和浮点错误,尤其是在测量周期很短或应用程序(或Windows计算机)正在长时间运行时。

perf_counter()大约100天后,分辨率开始下降。因此,例如,经过一年的正常运行时间后,它可以测量的最短间隔(大于0)将大于开始时的间隔。


Python 3.8更新

time.clock 现在不见了。


“在许多实现中,这些实际上可能是同一回事。” 没错,在我的Linux Mint PC上,time.monotonic()和time.perf_counter()似乎返回相同的值。
xjcl

7

更长的时间。

import time
start_time = time.time()
...
e = int(time.time() - start_time)
print('{:02d}:{:02d}:{:02d}'.format(e // 3600, (e % 3600 // 60), e % 60))

会打印

00:03:15

如果超过24小时

25:33:57

这是受到罗格·霍夫斯特(Rutger Hofste)的回答的启发。谢谢罗格!


6

您需要导入时间,然后使用time.time()方法知道当前时间。

import time

start_time=time.time() #taking current time as starting time

#here your code

elapsed_time=time.time()-start_time #again taking current time - starting time 

3

安排时间的另一种不错的方法是使用with python结构。

具有结构的对象会自动调用__enter____exit__方法,这正是我们计时所需的时间。

让我们创建一个Timer类。

from time import time

class Timer():
    def __init__(self, message):
        self.message = message
    def __enter__(self):
        self.start = time()
        return None  # could return anything, to be used like this: with Timer("Message") as value:
    def __exit__(self, type, value, traceback):
        elapsed_time = (time() - self.start) * 1000
        print(self.message.format(elapsed_time))

然后,可以使用Timer类,如下所示:

with Timer("Elapsed time to compute some prime numbers: {}ms"):
    primes = []
    for x in range(2, 500):
        if not any(x % p == 0 for p in primes):
            primes.append(x)
    print("Primes: {}".format(primes))

结果如下:

素数:[2、3、5、7、11、13、17、19、23、29、31、37、41、43、47、53、59、61、67、71、73、79、83、89 ,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227 ,229、233、239、241、251、257、263、269、271、277、281、283、293、307、311、313、317、331、337、347、349、353、359、367、373 ,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499]

计算一些质数所需的时间:5.01704216003418ms


2

Vadim Shender的反应很棒。您还可以使用以下更简单的装饰器:

import datetime
def calc_timing(original_function):                            
    def new_function(*args,**kwargs):                        
        start = datetime.datetime.now()                     
        x = original_function(*args,**kwargs)                
        elapsed = datetime.datetime.now()                      
        print("Elapsed Time = {0}".format(elapsed-start))     
        return x                                             
    return new_function()  

@calc_timing
def a_func(*variables):
    print("do something big!")

1

在编程中,有两种主要的时间测量方法,结果不同:

>>> print(time.process_time()); time.sleep(10); print(time.process_time())
0.11751394000000001
0.11764988400000001  # took  0 seconds and a bit
>>> print(time.perf_counter()); time.sleep(10); print(time.perf_counter())
3972.465770326
3982.468109075       # took 10 seconds and a bit
  • 处理器时间:这是该特定进程在CPU上主动执行所花费的时间。睡眠,等待Web请求或仅执行其他进程的时间不会对此有所帮助。

    • 采用 time.process_time()
  • 墙上时钟时间:这指的是“挂在墙上的时钟上”经过了多少时间,即不是实时时间。

    • 采用 time.perf_counter()

      • time.time() 还可以测量挂钟时间,但可以重置,因此您可以返回到过去
      • time.monotonic() 无法重置(单调=仅前进),但精度低于 time.perf_counter()

0

这是Vadim Shender的巧妙代码的更新,带有表格输出:

import collections
import time
from functools import wraps

PROF_DATA = collections.defaultdict(list)

def profile(fn):
    @wraps(fn)
    def with_profiling(*args, **kwargs):
        start_time = time.time()
        ret = fn(*args, **kwargs)
        elapsed_time = time.time() - start_time
        PROF_DATA[fn.__name__].append(elapsed_time)
        return ret
    return with_profiling

Metrics = collections.namedtuple("Metrics", "sum_time num_calls min_time max_time avg_time fname")

def print_profile_data():
    results = []
    for fname, elapsed_times in PROF_DATA.items():
        num_calls = len(elapsed_times)
        min_time = min(elapsed_times)
        max_time = max(elapsed_times)
        sum_time = sum(elapsed_times)
        avg_time = sum_time / num_calls
        metrics = Metrics(sum_time, num_calls, min_time, max_time, avg_time, fname)
        results.append(metrics)
    total_time = sum([m.sum_time for m in results])
    print("\t".join(["Percent", "Sum", "Calls", "Min", "Max", "Mean", "Function"]))
    for m in sorted(results, reverse=True):
        print("%.1f\t%.3f\t%d\t%.3f\t%.3f\t%.3f\t%s" % (100 * m.sum_time / total_time, m.sum_time, m.num_calls, m.min_time, m.max_time, m.avg_time, m.fname))
    print("%.3f Total Time" % total_time)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.