6

datetime.utcnow().secondがゼロのときに、毎分 1 回ループを実行したいと考えています。これまでのところ、私はこれを持っています

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

しかし、これの問題は、CPU プロセスを無駄にしていることです。を使用しますが、時間の経過とともに公式の UTC 時間から逸脱する可能性がtime.sleep(60)あるため、UTC クロックとどのように同期するかわかりません。time.sleep(60)

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

これは、次の分に到達するのに必要な時間だけ、1 秒未満の精度でスリープします。

分のロールオーバーのバグを修正するために編集されました。

于 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

単純なアプローチでは、 を に変更しすぎpasssleep (1)CPU の負荷が大幅に軽減されますが、何らかの理由12:30:59.9999912:31:01.00001.

2 段階のアプローチを選択できます。残り 3 秒以上ある場合は、残りの時間に基づいて、より長い時間待機します。それ以外の場合は、1 秒待ちます。

次の完全に機能する 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

それはあなたが求めているものです。

この関数は基本的に、分の終わりに非常に近づくまで 1 回の待機を行い、サイクルが終了するまで毎秒ウェイクアップします。

たとえば、それが であるとしましょう12:21:13secs未満ですので、程度までお持ちいただくのに十分か57お待ちいただくことになります。57 - 1312:21:57

そこから、secondが 未満になるまで、一度に 1 秒ずつ単純にスリープし57ます。言い換えれば、次の分に入るときです。

ゼロ秒を検出しようとするのではなく、このようにすることで、1 分を逃す可能性も回避できます。

また、ロールオーバーにできるだけ近づけたい場合は、 を に置き換えることができsleep (1)ますpass。そうすれば、最大で 60 秒中 3 秒 (平均 5%) の間、フル CPU のうなり声で実行し、可能な限り分単位のロールオーバーに近づけることができます。

その小さな変更を実行すると、次のようになります。

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 に答える