6

datetime.utcnow().second我希望在零时每分钟执行一次循环。到目前为止我有这个

while True:
    while datetime.utcnow().second != 0: pass
    do_something()

但问题是我在浪费 cpu 进程。我会使用time.sleep(60),但我不知道它如何与 UTC 时钟同步,因为time.sleep(60)随着时间的推移可能会偏离官方的 UTC 时间。

4

3 回答 3

16

我能想到的最好方法是睡到下一分钟:

while True:
    sleeptime = 60 - datetime.utcnow().second
    time.sleep(sleeptime)
    ...

如果你想非常精确:

while True:
    t = datetime.utcnow()
    sleeptime = 60 - (t.second + t.microsecond/1000000.0)
    time.sleep(sleeptime)
    ...

这会以亚秒级精度准确地休眠到达下一分钟所需的时间。

编辑修复分钟翻转错误。

于 2012-08-25T03:59:55.663 回答
2

有趣的问题 python 确实有一种方法可以使用sched来安排事件并让它再次发生,你可以一次又一次地安排它等等......

这里会是什么样子。

>>> import sched, time, datetime
>>> sch = sched.scheduler(time.time, time.sleep)
>>> 
>>> count = 0
>>> last = 0
>>> def do_something():
...     global count, last
...     if count != 5:
...         sch.enter(5, 1, do_something, ())
...     print datetime.datetime.now() - last
...     last = datetime.datetime.now()
...     count += 1
... 
>>> sch.enter(5, 1, do_something, ())
Event(time=1345872167.9454501, priority=1, action=<function do_something at 0x1004c4a28>, argument=())
>>> last = datetime.datetime.now()
>>> sch.run()

0:00:05.000015
0:00:05.000159
0:00:05.000184
0:00:05.000183
0:00:05.000181
0:00:05.000148
>>>

有趣的是,它似乎非常准确,可能由于执行实际指令所需的时间而产生了轻微的开销,我想如果我们想要完美的准确性,我们需要考虑它们......

于 2012-08-25T04:54:48.280 回答
0

天真的方法过于将 更改pass为 a sleep (1),这将大大减轻 CPU 压力,但如果由于某种原因12:30:59.9999912:31:01.00001.

您可以选择两阶段方法。虽然还有超过三秒钟的时间,但根据需要的时间等待更长的时间。否则,请等待一秒钟。

类似以下功能齐全的 Python 程序的东西将说明我的意思:

from datetime import datetime
from time import sleep

def WaitForNextMinute():
    secs = datetime.utcnow().second
    while secs < 57:
        sleep (57 - secs)
        secs = datetime.utcnow().second
    while datetime.utcnow().second >= 57:
        sleep (1)

while True:
    WaitForNextMinute()
    print datetime.utcnow()

我的系统上的输出是:

2012-08-25 04:16:00.111257
2012-08-25 04:17:00.157155
2012-08-25 04:18:00.217356
2012-08-25 04:19:00.270348
2012-08-25 04:20:00.330203
2012-08-25 04:21:00.390318
2012-08-25 04:22:00.450440
2012-08-25 04:23:00.510491
2012-08-25 04:24:00.570487
2012-08-25 04:25:00.630502
2012-08-25 04:26:00.690523
2012-08-25 04:27:00.750642
2012-08-25 04:28:00.810780
2012-08-25 04:29:00.870900
2012-08-25 04:30:00.931078

这几乎就是你所追求的。

这个函数基本上会做一个等待,让你非常接近一分钟结束,然后每秒醒来,直到它循环结束。

因此,例如,假设它是12:21:13. 因为secs是小于57,它会等待57 - 13或足以让你达到大约12:21:57

从那里开始,它会一次只休眠一秒钟,直到second小于57。换句话说,当我们进入下一分钟时。

通过这样做而不是尝试检测零秒,您还可以绕过错过一分钟的可能性。

而且,如果您想确保尽可能接近分钟翻转,您可以将 替换sleep (1)pass. 这样,您将在 60 秒(平均 5%)中以全 CPU 运行最多三秒(平均 5%),并尽可能接近分钟翻转。

当我执行那个小修改时,我得到:

2012-08-25 05:48:00.000003
2012-08-25 05:49:00.000003
2012-08-25 05:50:00.000003
2012-08-25 05:51:00.000004
2012-08-25 05:52:00.000004
2012-08-25 05:53:00.000004
2012-08-25 05:54:00.000003
2012-08-25 05:55:00.000004
于 2012-08-25T04:03:37.487 回答