積雲が映像制作したMV『RANGEFINDER』公開中
専門88IO

【Python】タスクスケジュール管理方法

専門

例えばTodoリスト予約機能。複数タスクを直近順に並べたいことがある。

こんなときはヒープキュークラスの特殊メソッドを用いると上手くいく。

ヒープキュー

標準ライブラリheapqを活用する。優先度付きキューを生成することができ木構造によって管理されるため、直近タスクの取り出しを容易に行うことができる。

優先度の判定は要素ごとの比較演算、タプルの場合は第1引数が参照される。また、仕様上ヒープキューの第1要素が必ず最小要素となる。

import heapq as hq

heap = []

# heapに要素を追加
hq.heappush(heap, 10)
hq.heappush(heap, 1)
hq.heappush(heap, 5)

# heapから要素を取り出し
x = hq.heappop(heap)  # x = 1
x = hq.heappop(heap)  # x = 5
x = hq.heappop(heap)  # x = 10

クラスの特殊メソッド

特殊メソッド__lt__を実装することでクラス間の比較演算を行うことができる。

class User:
    def __init__(self, value):
        self.value = value
    
    def __lt__(self, other):
        if not isinstance(other, User):
            return NotImplemented
        return self.value < other.value

上の例はUserクラスをインスタンス変数valueで比較演算できるようにしている。これで以下のように扱えるようになる。

a = User(10)
b = User(15)

print(a < b)  # -> True

用例

複数タスクを保持し、直近のタスクから取り出して処理したい場合を考える。

今回は各タスクは情報として、

  • タスク名:name
  • 実行時刻:datetime

を持っていると仮定する。

実行時刻が近い順にタスクを参照したいのでヒープキューを用い、比較演算できない要素はヒープキューに挿入できないので特殊メソッドを実装する方針。

import datetime
import heapq as hq


# タスクの情報を保持するクラス
class Task:
    # 本来は引数要素の型チェックを行うが省略
    def __init__(self, name, datetime):
        self.name = name
        self.datetime = datetime
    
    def __lt__(self, other):
        if not isinstance(other, Task):
            return NotImplemented
        return self.datetime < other.datetime


tasks = []

# タスクの追加
hq.heappush(tasks, Task("タスクA", datetime.datetime(2021, 4, 1)))
hq.heappush(tasks, Task("タスクA", datetime.datetime(2021, 6, 1)))
hq.heappush(tasks, Task("タスクA", datetime.datetime(2021, 5, 1)))

# タスクが存在する間ループ
while tasks:
    # タスクを取り出したくない場合はtask[0]を参照すればよい
    # 実行時刻を超えたらタスクをキューから取り出して処理する
    if tasks[0] <= datetime.datetime.now():
        task = hq.heappop(tasks)
        # タスクに対する何らかの処理
    # スリープ処理等

コメント

タイトルとURLをコピーしました