21

python-daemonを使用する場合、次のようなサブプロセスを作成しています。

import multiprocessing

class Worker(multiprocessing.Process):
   def __init__(self, queue):
      self.queue = queue # we wait for things from this in Worker.run()

   ...

q = multiprocessing.Queue()

with daemon.DaemonContext():
    for i in xrange(3):
       Worker(q)

    while True: # let the Workers do their thing
       q.put(_something_we_wait_for())

Ctrl-C や SIGTERM などで親のデーモン プロセス (ワーカーではないプロセス) を強制終了しても、子プロセスは終了しません。どうやって子供を殺しますか?

私の最初の考えは、atexitを使用してすべてのワーカーを殺すことです。

 with daemon.DaemonContext():
    workers = list()
    for i in xrange(3):
       workers.append(Worker(q))

    @atexit.register
    def kill_the_children():
        for w in workers:
            w.terminate()

    while True: # let the Workers do their thing
       q.put(_something_we_wait_for())

ただし、デーモンの子は扱いが難しいため、これをどのように行うべきかについての考えと情報を提供していただきたいと思います。

ありがとうございました。

4

3 に答える 3

32

あなたのオプションは少し限られています。self.daemon = Trueクラスのコンストラクターで実行しWorkerても問題が解決せず、親 (つまり、SIGTERM, SIGINT) でシグナルをキャッチしようとしてもうまくいかない場合は、逆の解決策を試す必要がある場合があります。親に子を殺す代わりに、次のことができます。親が死んだら子供を自殺させる。

最初のステップは、コンストラクターを親プロセスWorkerのに与えるPIDことです (これは で行うことができますos.getpid())。次に、ワーカー ループ内で行う代わりに、self.queue.get()次のようにします。

waiting = True
while waiting:
    # see if Parent is at home
    if os.getppid() != self.parentPID:
        # woe is me! My Parent has died!
        sys.exit() # or whatever you want to do to quit the Worker process
    try:
        # I picked the timeout randomly; use what works
        data = self.queue.get(block=False, timeout=0.1)
        waiting = False
    except queue.Queue.Empty:
        continue # try again
# now do stuff with data

上記の解決策は、親の PID が元の PID と異なるかどうか (つまり、子プロセスが採用されたか、initまたはlauchd親プロセスが停止したために発生したかどうか) を確認します。参照を参照してください。ただし、何らかの理由でそれが機能しない場合は、次の関数に置き換えることができます (ここから適応):

def parentIsAlive(self):
    try:
        # try to call Parent
        os.kill(self.parentPID, 0)
    except OSError:
        # *beeep* oh no! The phone's disconnected!
        return False
    else:
        # *ring* Hi mom!
        return True

今度は、親が (何らかの理由で) 死ぬと、子ワーカーがハエのように自然にドロップします。:-D

于 2010-04-09T21:04:08.627 に答える
4

子が最初に作成されたときに親 pid を保存する必要があり (たとえば でself.myppid) 、親が死亡したことを意味するときself.myppidとは異なります。getppid()

親が何度も変更されたかどうかを確認することを避けるために、シグナルのドキュメントPR_SET_PDEATHSIGで説明されているそれを使用できます。

5.8 Linux の「親の死」シグナル

各プロセスには変数 pdeath_signal があり、fork() または clone() の後に 0 に初期化されます。親プロセスが終了したときにプロセスが受け取るべきシグナルを提供します。

この場合、プロセスを終了させたい場合は、次のSIGHUPように a に設定できます。

prctl(PR_SET_PDEATHSIG, SIGHUP);
于 2010-04-09T21:23:02.377 に答える
2

Atexit はこのトリックを実行しません。非シグナル終了が成功した場合にのみ実行されます。ドキュメントの上部にある注を参照してください。2 つの方法のいずれかでシグナル処理をセットアップする必要があります。

より簡単に聞こえるオプション: http://docs.python.org/library/multiprocessing.html#process-and-exceptionsに従って、ワーカー プロセスにデーモン フラグを設定します。

やや難しいオプション: PEP-3143は、python-daemon でプログラムのクリーンアップのニーズをフックする組み込みの方法があることを暗示しているようです。

于 2010-04-07T16:44:18.823 に答える