在循环期间每x秒输出值的最佳/最有效方法是什么

时间:2014-08-26 19:44:23

标签: python

我一直对此感到好奇,因为简单的方法绝对不高效。你会如何有效地每隔x秒输出一次值?

这是我的意思的一个例子:

import time
num = 50000000

startTime = time.time()
j=0
for i in range(num):
    j = (((j+10)**0.5)**2)**0.5
print time.time() - startTime

#output time: 24 seconds


startTime = time.time()
newTime = time.time()
j=0
for i in range(num):
    j = (((j+10)**0.5)**2)**0.5
    if time.time() - newTime > 0.5:
        newTime = time.time()
        print i
print time.time() - startTime

#output time: 32 seconds

每半秒输出一次进度,速度提高1/3。

我知道这是因为它需要在每个循环中进行额外的计算,但是同样适用于您可能想要做的其他类似检查 - 如何在不严重影响执行时间的情况下实现类似的操作?

6 个答案:

答案 0 :(得分:2)

您可以通过跟踪下次打印到期来节省几个时钟周期

nexttime = time.time() + 0.5

然后你的情况将是一个简单的比较

If time.time()  >= nexttime

与减法相比,而不是比较

If time.time() - newTime > 0.5

您只需在每条消息后添加一个添加内容,而不是在每次消息后进行减法

答案 1 :(得分:2)

嗯,你知道你每秒进行多次迭代,所以你真的不需要在每次迭代时进行time.time()调用。您可以使用模运算符来实际检查是否需要在循环的每N次迭代中输出一些内容。

startTime = time.time()
newTime = time.time()
j=0
for i in range(num):
    j = (((j+10)**0.5)**2)**0.5
    if i % 50 == 0:  # Only check every 50th iteration
        if time.time() - newTime > 0.5:
            newTime = time.time()
            print i, newTime
print time.time() - startTime
# 45 seconds (the original version took 42 on my system)

仅检查每50次迭代会将我的运行时间从56秒减少到43(原始版本没有打印42,而Tom Page的解决方案需要50秒),并且迭代完成得足够快以至于它仍然完全输出根据{{​​1}}:

每0.5秒
time.time()

答案 2 :(得分:1)

我尝试使用边带线程进行打印。它在python 2.x上添加了5秒的执行时间,但在python 3.x上几乎没有额外的时间。 Python 2.x线程有很多开销。这是我的例子,时间包括在评论中:

import time
import threading


def showit(event):
    global i # could pass in a mutable object instead
    while not event.is_set():
        event.wait(.5)
        print 'value is', i

num = 50000000

startTime = time.time()
j=0
for i in range(num):
    j = (((j+10)**0.5)**2)**0.5
print time.time() - startTime

#output time: 23 seconds

event = threading.Event()
showit_thread = threading.Thread(target=showit, args=(event,))
showit_thread.start()

startTime = time.time()
j=0
for i in range(num):
    j = (((j+10)**0.5)**2)**0.5
event.set()
time.sleep(.1)
print time.time() - startTime

#output time: 28 seconds

答案 3 :(得分:0)

如果您想在做某事之前等待一段指定的时间,请使用time.sleep()方法。

for i in range(100):
    print(i)
    time.sleep(0.5)

在打印下一个i值之前,这将等待半秒钟。

答案 4 :(得分:0)

如果您不关心Windows,signal.setitimer将比使用后台线程更简单,并且在许多* nix平台上效率更高。

以下是一个例子:

import signal
import time

num = 50000000

startTime = time.time()

def ontimer(sig, frame):
    global i
    print(i)
signal.signal(signal.SIGVTALRM, ontimer)

signal.setitimer(signal.ITIMER_VIRTUAL, 0.5, 0.5)
j=0
for i in range(num):
    j = (((j+10)**0.5)**2)**0.5
signal.setitimer(signal.ITIMER_VIRTUAL, 0)
print(time.time() - startTime)

这几乎是免费的,因为你将获得表现明智。

在某些用例中,虚拟计时器不够准确,因此您需要将其更改为ITIMER_REAL并将信号更改为SIGALRM。这有点贵,但仍然很便宜,而且还很简单。

在某些(较旧的)* nix平台上,alarm可能比setitmer更有效,但遗憾的是alarm只需要整秒,因此您无法使用它来发射两次/秒。

来自MacBook Pro的时间:

  • 无输出:15.02s
  • SIGVTALRM:15.03s
  • SIGALRM:15.44s
  • 主题:19.9s
  • 检查time.time():22.3s

(我没有使用dano的优化或Tom Page进行测试;显然这些会减少22.3,但是它们不会降低到15.44 ......)

答案 5 :(得分:0)

这里的部分问题是你正在使用time.time

在我的MacBook Pro上,只要您正在完成的所有工作,time.time所需的时间就超过1/3:

In [2]: %timeit time.time()
10000000 loops, best of 3: 105 ns per loop

In [3]: %timeit  (((j+10)**0.5)**2)**0.5
1000000 loops, best of 3: 268 ns per loop

对于time,105ns fast - 例如,没有比ACPI更好的硬件计时器的旧Windows机箱可能需要100倍的时间。


最重要的是,time.time并不能保证足够的精确度来做你想要的事情:

  

请注意,即使时间始终作为浮点数返回,但并非所有系统都提供的精度高于1秒。

即使在精度高于1秒的平台上,它的精度也可能较低;例如,每个调度程序滴答只能更新一次。

并且time甚至不能保证单调;在某些平台上,如果系统时间发生变化,time可能会下降。


较少调用它将解决第一个问题,但不能解决其他问题。

那么,你能做什么?

不幸的是,没有内置的答案,至少没有Python 2.7。最佳解决方案在不同平台上有所不同 - 可能是GetTickCount64在Windows上,clock_gettime在大多数现代* nix上具有适当的时钟ID,在大多数其他* nix上具有gettimeofday。如果您不想分发C扩展,这些相对容易通过ctypes使用...但有人真的应该将它全部包装在模块中并将其发布在PyPI上,不幸的是我找不到一个...