22

で使用しようとしていますatexitProcess、残念ながら機能していないようです。コード例を次に示します。

import time
import atexit
import logging
import multiprocessing

logging.basicConfig(level=logging.DEBUG)

class W(multiprocessing.Process):
    def run(self):
        logging.debug("%s Started" % self.name)

        @atexit.register
        def log_terminate():
             # ever called?
             logging.debug("%s Terminated!" % self.name)

        while True:
            time.sleep(10)

@atexit.register
def log_exit():
    logging.debug("Main process terminated")

logging.debug("Main process started")

a = W()
b = W()
a.start()
b.start()
time.sleep(1)
a.terminate()
b.terminate()

このコードの出力は次のとおりです。

DEBUG:root:メイン プロセスが開始されました
DEBUG:root:W-1 開始
DEBUG:root:W-2 開始
DEBUG:root:メイン プロセスが終了しました

W.run.log_terminate()とが呼び出されたときa.terminate()にが呼び出され、出力が次のようになることを期待しb.terminate()ます (強調を追加)!:

DEBUG:root:メイン プロセスが開始されました
DEBUG:root:W-1 開始
DEBUG:root:W-2 開始
DEBUG:root:W-1 終了しました!
DEBUG:root:W-2 終了しました!
DEBUG:root:メイン プロセスが終了しました

なぜこれが機能しないのですか? また、 aが終了Processしたときに (コンテキストから)メッセージをログに記録するより良い方法はありますか?Process

ご意見をお寄せいただきありがとうございます。

解決

編集: Alex Martelli によって提案された解決策に基づいて、次は期待どおりに機能します。

import sys
import time
import atexit
import signal
import logging
import multiprocessing

logging.basicConfig(level=logging.DEBUG)

class W(multiprocessing.Process):
    def run(self):
        logging.debug("%s Started" % self.name)

        def log_terminate(num, frame):
             logging.debug("%s Terminated" % self.name)
             sys.exit()
        signal.signal(signal.SIGTERM, log_terminate)
        while True:
            time.sleep(10)

@atexit.register
def log_exit():
    logging.debug("Main process terminated")

logging.debug("Main process started")
a = W()
b = W()
a.start()
b.start()
time.sleep(1)
a.terminate()
b.terminate()

atexitドキュメントの次のコメントに注意してください。

注: このモジュールを介して登録された関数は、プログラムがシグナルによって強制終了されたとき、Python の致命的な内部エラーが検出されたとき、または os._exit() が呼び出されたときに呼び出されません。
4

1 に答える 1

18

ドキュメントが言うように、

Unix では、これは SIGTERM シグナルを使用して行われます。Windows では TerminateProcess() が使用されます。exit ハンドラや finally 句などは実行されないことに注意してください。

Unix を使用している場合は、 signalSIGTERMでインターセプトし、必要な「終了アクティビティ」を実行できるはずです。ただし、クロスプラットフォーム ソリューションについては知りません。

于 2010-03-30T15:20:16.370 に答える