4

特定の間隔で実行する必要があるプログラムがあります。たとえば、5 分ごとに実行したい場合があります。複数のエンド ノード デバイスと通信する複数のコーディネータがあります。以下のコードはコーディネーターにあります。が 5 に設定されている場合、intervalたとえば 9: 05、9:10、9:15、9:20、9:25などで実行され、情報が記録されるようにする必要があります。これまでのコードは次のように:

if __name__ == '__main__':
    while True:
        try:
            r = json.read(rqst_command())
            interval = r.get('intvl')
            collect_time = r.get('c_time')
            command = r.get('cmd')
            send_stats(cmd_nodes(command, collect_time))
            time.sleep(interval)
        except Exception, e:
            print e
            print "**Top Level Exception"
            pass

問題は、間隔を5 分に設定すると、正確に 5 分ごとに記録されないことです。実行時間はその時間をゆっくりと増やしているようです。たとえば、上記のコードは9:05:09、9:10:19、9:15:29、9:20:41、9:25:50 と記録される場合があります。プログラムの実行にかかる時間は、ノードの通信速度によって異なります。

プログラムが5分ごとに正確に実行されるようにコードを変更する方法について、誰かアイデアはありますか?

編集/更新

私は自分の問題を処理する方法を考え出したと思います。私は電流をつかみ、datetimeそれが 5 分のマークにあるかどうかを確認します。その場合は、 を記録datetimeして関数に送信しsend_statsます。そうdatetimeすれば、常に私が望んでいるものとまったく同じになります。5分経過していない場合はsleep、しばらくしてからもう一度確認してください。私はコードをほとんど完成させました。ただし、プログラムを実行すると次のエラーが発生します: 'builtin_function_or_method' object has no attribute 'year'.

私は間違って何をしていますか?

これが私の新しいコードです:

import os
import json
import datetime
from datetime import datetime
import urllib2
from urllib import urlencode
from socket import *
import time
import zigbee
import select

if __name__ == '__main__':
        while True:
            try:
                r = json.read(rqst_command())
                interval = r.get('intvl')
                collect_time = r.get('c_time')
                command = r.get('cmd')

                tempTest = True

                while tempTest == True:
                    start_time = datetime.now
                    compare_time = datetime(start_time.year, start_time.month, start_time.day, start_time.hour, 0, 0)
                    difff = int((start_time - compare_time).total_seconds() / 60)

                    if((difff % interval) == 0):
                        c_t = datetime(start_time.year, start_time.month, start_time.day, start_time.hour, start_time.minute, 0)
                        send_stats(cmd_nodes(command, collect_time), c_t)
                        tempTest = False
                    else:
                        time.sleep(30)              
            except Exception, e:
                print e
                print "**Top Level Exception"
                pass
4

6 に答える 6

3

以下のコードは、私の問題を解決したものです。間隔が何であれ、常にdatetime各時間の開始時に開始し、間隔ごとに増分します。したがって、間隔が 5 の場合、次のようにdatetime表示されます: 9:00:00、9:05: 00、9:10:00、9:15:00、9 :20:00、9:25:00など。間隔が 3 の場合、次のようにdatetime表示されます: 5:00: 00、5:03:00、5:06:00、5:09:00、5:12:00、5:15:00、およびなど。コーディネータはエンド ノードからデータを取得し、datetime.

if __name__ == '__main__':
    last_minute = -1

    while True:
        try:
            r = json.read(rqst_command())
            print r
            command = r.get('cmd')
            interval = r.get('intvl')
            collect_time = r.get('c_time')

            tempTest = True

            while tempTest == True:
                start_time = datetime.now()
                s_minute = start_time.minute

                if(((s_minute % interval) == 0) and (s_minute != last_minute)):
                    tempTest = False
                    c_t = datetime(start_time.year, start_time.month, start_time.day, start_time.hour, start_time.minute, 0)
                    last_minute = c_t.minute

                    send_stats(cmd_nodes(command, collect_time), c_t)
                    time.sleep(1)
                else:
                    time.sleep(1)
        except Exception, e:
            print e
            print "**Top Level Exception"
            pass
于 2012-09-01T01:50:17.660 に答える
2

他の人が指摘しているように、cron のようなすぐに使用できるジョブ/タスク スケジューラが既に存在します。あなたはそれらを使うことができます。しかし、Python で独自の単純なソリューションを実装することもできます。これは問題ありません。正しい方法で行うだけです。あなたのアプローチの根本的な問題は、アクション間の一定の間隔でスリープし、システム時間を定期的にチェックしないことです。あなたの方法では、アクションの持続時間は時間測定の誤差です。そして、このエラーは各アクションで要約されます。このエラーのない時間参照 (システム時間) が必要です。

実装例: たとえば、1 秒の精度で十分だと考えてください。次に、ループ内で 1 秒ごとにシステム時刻を確認します。これは、 で安全に実現できますtime.sleep(1)。たとえば、システム時刻がlast_action_execution_time(明らかにどこかに保存した) よりも 5 分遅れている場合は、現在の時刻を として保存しlast_action_execution_time、アクションを実行します。このアクションが確実に 5 分未満続く限り、次の実行はlast_action_execution_time + 5 minごくわずかなエラーで発生します。最も重要なことは、このエラーが実行時に実行回数とともに増加しないことです。

信頼できる Python ベースのソリューションについては、http://docs.python.org/library/sched.htmlも参照してください。

于 2012-08-30T13:57:13.083 に答える
2

どうですか:

while true:
    try:

        start=time.time() # save the beginning time before execution starts

        r = json.read(rqst_command())
        interval = r.get('intvl')
        collect_time = r.get('c_time')
        command = r.get('cmd')
        start_time = datetime.now()
        send_stats(cmd_nodes(command, collect_time))
        end_time = datetime.now()
        sleepy_time = interval - (end_time - start_time)

        while time.time() <= start + sleepy_time*60: #To wait until interval has ended note: I'm assuming sleepy_time is in minutes.
            pass

    except Exception, e:
    print e
    print "**Top Level Exception"
    pass
于 2012-08-31T21:06:36.037 に答える
1

Pythonでこれを実行し、他のシステムに依存しないことを前提としています。

プロセスがいつ開始し、いつ終了するかを考慮し、それに応じて間隔を設定する必要があります。コードは次のようになります。

if __name__ == '__main__':
while True:
    try:
        r = json.read(rqst_command())
        interval = r.get('intvl')
        collect_time = r.get('c_time')
        command = r.get('cmd')
        start_time = datetime.now()
        send_stats(cmd_nodes(command, collect_time))
        end_time = datetime.now()
        sleepy_time = interval - (end_time - start_time)
        time.sleep(sleepy_time)
    except Exception, e:
        print e
        print "**Top Level Exception"
        pass
于 2012-08-30T14:04:43.663 に答える
1

Linux を使用している場合は、特定の間隔でスクリプトを実行するcronjobをセットアップすることをお勧めします。

于 2012-08-30T13:51:57.333 に答える
1

これには 2 つの方法があります。

最初の最良の方法は、OS のタスク スケジューラ (Windows ではタスク スケジューラ、cronLinux ではタスク スケジューラ) を使用することです。これらのツールの開発者はおそらく、あなたが想像するよりも多くの問題を予想していたでしょう。コードを自分で行う必要がないことは時間であり、おそらくバグを救うことにもなります。

それ以外の場合は、スクリプトの実行時間を考慮する必要があります。これを行う最も簡単な方法は、インターバルの間スリープする代わりに (ゆっくりと前方にスライドするのを見たように)、最後に目が覚めた時間に基づいて次に実行する必要がある時期を計算し、実行後、インターバルの間だけスリープすることです。今とそれの間。

于 2012-08-30T13:55:53.307 に答える