5

私は最近 Python の学習を始めました。私が作成している単純なアプリの一部には、独自のスレッドで実行される hh:mm:ss 表示のタイマーが含まれています。

Web を見回すと、これを実装する 2 つの方法が見つかりました。

  1. sched.scheduler の使用
  2. threading.Timer の使用

私が行った方法は、両方の実装で似ています。

スケジュール:

def tick(self, display, alarm_time):

    # Schedule this function to run every minute
    s = sched.scheduler(time.time, time.sleep)
    s.enter(1, 1, self.tick, ([display, alarm_time]))

    # Update the time
    self.updateTime(display)

タイマー:

def tick(self, display):

    # Schedule this function to run every second
    t = Timer(1, self.tick, (display,alarm_time))
    t.start()

    # Update the time
    self.updateTime(display)
  1. 正しく刻むことに関しては問題なく動作しますが、数分後に次のエラーが生成されます: RuntimeError: 最大再帰深度を超えました。最大再帰レベルを手動で増やすことができることは知っていますが、ここではこれは必要ないはずですか?

  2. エラーはありませんが、時折、秒がスキップしたり、不規則にカチカチ音をたてたりします。

これを正しく行う方法について、誰かが私を正しい方向に向けることができますか? ありがとうございました。

4

2 に答える 2

5

関数が独自のスケジューラschedを作成し、そのスレッドで実行される唯一のものである必要がある場合:

def tick(self, display, alarm_time, scheduler=None):
  # make a new scheduler only once & schedule this function immediately
  if scheduler is None:
    scheduler = sched.scheduler(time.time, time.sleep)
    scheduler.enter(0, 1, self.tick, ([display, alarm_time, scheduler]))
    scheduler.run()

  # reschedule this function to run again in a minute
  scheduler.enter(1, 1, self.tick, (display, alarm_time, scheduler]))

  # do whatever actual work this function requires, e.g.:
  self.updateTime(display)

他のイベントも同じスレッドでスケジュールする必要がある場合は、スケジューラを「別の場所」で作成して所有する必要があります。if上記の部分は、別のメソッドにリファクタリングできます。たとえば、次のようになります。

def scheduleperiodic(self, method, *args):
  self.scheduler = sched.scheduler(time.time, time.sleep)
  self.scheduler.enter(0, 1, method, args)
  # whatever else needs to be scheduled at start, if any, can go here
  self.scheduler.run()

def tick(self, display, alarm_time):
  # reschedule this function to run again in a minute
  self.scheduler.enter(60, 1, self.tick, (display, alarm_time))

  # do whatever actual work this function requires, e.g.:
  self.updateTime(display)

繰り返しますが、もちろん、いつものようにsched、スケジューラが実行されている間、スケジューラ (およびスケジュールされたイベント コールバック) が問題のスレッドを「引き継ぐ」ことになります (したがって、他のスレッドが必要な場合は、別のスレッドをハイブオフする必要があります)。同時に起こっていること)。

この種のイディオムを多くの関数で使用する必要がある場合は、デコレーターにリファクタリングできますが、それはイディオムの根底にある単純さをいくらか隠してしまうので、私はこの単純で明白な使用を好みます。ところで、time.time と time.sleep は時間の単位として分ではなく秒を使用することに注意してください。したがって、「今から 1 分後」を示すには 1 ではなく 60 が必要です;-)。

于 2009-09-10T15:57:34.487 に答える
4

タイマーはワンショットイベントです。このようにループさせることはできません。

タイマーを使用して関数を呼び出し、次に別のタイマーを作成して、タイマーを作成する関数を呼び出し、タイマーを作成する関数を呼び出す、...は、再帰制限に到達する必要があります。

OSについては言及していませんが、「スキップ」または「不規則にチェック」するのには2つの理由があります。

  1. あなたのコンピュータは忙しく、「1秒」は「他に何が起こっているかに応じて、1秒にかなり近い」ことを意味します

  2. タイマーを0.9999秒で開始し、1秒待つと、1.9999(1に切り捨て)または2.00000になる可能性があります。時間を複製したり、時間をスキップしたりするように見える場合があります。コンピュータの内部ハードウェアクロックは非常に正確であり、最も近い秒に四捨五入すると、(常に)重複またはスキップの可能性が低くなります。

schedを正しく使用してください。 http://docs.python.org/library/sched.html#module-sched

コードスニペットは、schedにも意味がありません。新しいスケジューラオブジェクトを作成する必要はありません。新しいイベントを作成するだけです。

既存のスケジューラインスタンスの新しいイベントの作成については、http://docs.python.org/library/sched.html#sched.scheduler.enterをお読みください。

于 2009-09-10T10:58:35.657 に答える