0

私が取り組んでいるアプリのモジュールの 1 つは、Linux で長時間実行されるプロセスとして使用することを目的としており、SIGTERM、SIGHUP、およびその他のシグナルを適切に処理したいと考えています。プログラムのコア部分は、実際には関数を定期的に実行するループです (別のスレッドを起動しますが、これはそれほど重要ではありません)。多かれ少なかれ次のようになります。

while True: 
    try:
        do_something()
        sleep(60)
    except KeyboardInterrupt:
        break

cleanup_and_exit()

KeyboardInterruptここで追加したいのは、例外と同じように、SIGTERM をキャッチしてループを終了することです。

私が考えていることの 1 つは、シグナル ハンドラー関数によって True に設定されるフラグを追加し、sleep(60) を sleep(0.1) などに置き換えて、秒をカウントするカウンターに置き換えることです。

_exit_flag = False
while not _exit_flag: 
    try:
        for _ in xrange(600): 
            if _exit_flag: break
            do_something()
            sleep(0.1)

    except KeyboardInterrupt:
        break

cleanup_and_exit()

そして他の場所:

def signal_handler(sig, frame): 
    _exit_flag = True

しかし、これが最善/最も効率的な方法であるかどうかはわかりません。

4

1 に答える 1

1

メイン ループでセンチネルを使用して、実際に確認したいよりも頻繁に起動する必要があるのではなく、クリーンアップをハンドラーにプッシュしないでください。何かのようなもの:

class BlockingAction(object):

    def __new__(cls, action):

        if isinstance(action, BlockingAction):
           return action
        else:
           new_action = super(BlockingAction, cls).__new__(cls)
           new_action.action = action
           new_action.active = False
           return new_action

    def __call__(self, *args, **kwargs):

        self.active = True
        result = self.action(*args, **kwargs)
        self.active = False
        return result

class SignalHandler(object):

    def __new__(cls, sig, action):

        if isinstance(action, SignalHandler):
            handler = action
        else:
            handler = super(SignalHandler, cls).__new__(cls)
            handler.action = action
            handler.blocking_actions = []
        signal.signal(sig, handler)
        return handler

    def __call__(self, signum, frame):

        while any(a.active for a in self.blocking_actions):
            time.sleep(.01)
        return self.action()

    def blocks_on(self, action):

        blocking_action = BlockingAction(action)
        self.blocking_actions.append(blocking_action)
        return blocking_action

def handles(signal):

    def get_handler(action):

        return SignalHandler(signal, action)

    return get_handler

@handles(signal.SIGTERM)
@handles(signal.SIGHUP)
@handles(signal.SIGINT)
def cleanup_and_exit():
    # Note that this assumes that this method actually exits the program explicitly
    # If it does not, you'll need some form of sentinel for the while loop
    pass

@cleanup_and_exit.blocks_on
def do_something():
    pass

while True:
    do_something()
    time.sleep(60)
于 2013-01-02T16:36:13.000 に答える