sched – 汎用イベントスケジューラ

目的:汎用イベントスケジューラ
利用できるバージョン:1.4 以上

sched モジュールは、特定時刻にタスクを実行する汎用イベントスケジューラを実装します。スケジューラクラスは、現在の時間を知るために time 関数を、一定時間待つために delay 関数を使用します。実際の時間の単位は、多目的に使用できるように柔軟なインターフェイスを設ければ重要ではありません。

time 関数は、引数なしで呼ばれ、現在の時間を表す数値を返します。 delay 関数は、 time 関数と同じ単位で1つの整数を引数に取り、時間単位分を待ちます。例えば、 time.time()time.sleep() 関数はこれらの要件を満たします。

マルチスレッドアプリケーションをサポートするには、その他のスレッドの実行機会があることを保証するために、各イベントが生成された後で delay 関数の引数を0で呼び出します。

イベントを遅延なく実行する

イベントは、遅延後または一定時間後に実行するようにスケジュールできます。遅延させてスケジュールするには、4つの引数を受け取る enter() を使用してください。

  • 遅延を表す値
  • 優先順位の値
  • 呼び出す関数
  • 関数の引数のタプル

このサンプルでは、予定の違う2つのイベントがそれぞれ2後後と3秒後に実行されます。イベントを実行する時間がきたら、 print_event() が呼び出されて、現在の時間とイベントに渡された name 引数を表示します。

import sched
import time

scheduler = sched.scheduler(time.time, time.sleep)

def print_event(name):
    print 'EVENT:', time.time(), name

print 'START:', time.time()
scheduler.enter(2, 1, print_event, ('first',))
scheduler.enter(3, 1, print_event, ('second',))

scheduler.run()

この結果出力は次のようになります。

$ python sched_basic.py
START: 1361118798.28
EVENT: 1361118800.28 first
EVENT: 1361118801.28 second

最初のイベントは開始して2秒後に、2番目のイベントは開始して3秒後に表示されます。

イベントを重複させる

全てのイベントが処理されるまで run() の呼び出しはブロックします。それぞれのイベントは同じスレッドで実行されるので、あるイベントがイベント間の遅延時間よりも実行に時間がかかる場合に重複します。このイベントの重複は、それ以降のイベントを延期することで解決されます。イベントがなくなるわけではありませんが、予定した時間よりも遅れてイベントが実行される可能性があります。次の例では、 long_event()sleep しますが、時間のかかる計算を実行するか、I/O をブロッキングすることで簡単に遅延させられます。

import sched
import time

scheduler = sched.scheduler(time.time, time.sleep)

def long_event(name):
    print 'BEGIN EVENT :', time.time(), name
    time.sleep(2)
    print 'FINISH EVENT:', time.time(), name

print 'START:', time.time()
scheduler.enter(2, 1, long_event, ('first',))
scheduler.enter(3, 1, long_event, ('second',))

scheduler.run()

その結果、最初のイベントは2番目のイベントの開始時刻を過ぎるまでかかるので、最初のイベント終了後すぐに2番目のイベントが実行されます。

$ python sched_overlap.py
START: 1361118801.35
BEGIN EVENT : 1361118803.35 first
FINISH EVENT: 1361118805.35 first
BEGIN EVENT : 1361118805.35 second
FINISH EVENT: 1361118807.35 second

イベントの優先度

同じ時間に1つ以上のイベントが予定されている場合、実行する順番を決めるために優先度の値が使用されます。

import sched
import time

scheduler = sched.scheduler(time.time, time.sleep)

def print_event(name):
    print 'EVENT:', time.time(), name

now = time.time()
print 'START:', now
scheduler.enterabs(now+2, 2, print_event, ('first',))
scheduler.enterabs(now+2, 1, print_event, ('second',))

scheduler.run()

このサンプルは、厳密に同じ時間に予定されていることを保証する必要があるので、 enter() ではなく enterabs() メソッドを使用します。 enterabs() の最初の引数は、遅延の時間ではなくイベントを実行する時間です。

$ python sched_priority.py
START: 1361118807.4
EVENT: 1361118809.4 second
EVENT: 1361118809.4 first

イベントをキャンセルする

enter()enterabs() の両方とも、後でキャンセルできるリファレンスを返します。 run() はブロックしてしまうので、イベントは違うスレッドからキャンセルさせる必要があります。このサンプルでは、別のスレッドがスケジューラを実行するために開始されて、メイン処理のスレッドがそのイベントをキャンセルするために使用されます。

import sched
import threading
import time

scheduler = sched.scheduler(time.time, time.sleep)

# スレッドが変更できるグローバル変数をセットする
counter = 0

def increment_counter(name):
    global counter
    print 'EVENT:', time.time(), name
    counter += 1
    print 'NOW:', counter

print 'START:', time.time()
e1 = scheduler.enter(2, 1, increment_counter, ('E1',))
e2 = scheduler.enter(3, 1, increment_counter, ('E2',))

# イベントを実行するスレッドを開始する
t = threading.Thread(target=scheduler.run)
t.start()

# メインスレッドに戻り、最初のイベントをキャンセルする
scheduler.cancel(e1)

# スケジューラのスレッドの実行が終わるまで待つ
t.join()

print 'FINAL:', counter

2つのイベントが予定されていましたが、最初のイベントはキャンセルされました。2番目のイベントのみ実行されるので、その counter 変数は1回だけインクリメントされます。

$ python sched_cancel.py
START: 1361118809.46
EVENT: 1361118812.47 E2
NOW: 1
FINAL: 1

See also

sched
本モジュールの標準ライブラリドキュメント
time
time モジュール
Bookmark and Share