6

Pythonデーモンプロセス内でマルチプロセッシングモジュールを使用すると(python-daemonを使用)、次のエラーが発生します。

トレースバック(最後の最後の呼び出し):
  _run_exitfuncsのファイル"/usr/local/lib/python2.6/atexit.py"、24行目
    func(* targs、** kargs)
  _exit_functionのファイル"/usr/local/lib/python2.6/multiprocessing/util.py"、行262
    active_children()のpの場合:
  active_childrenのファイル"/usr/local/lib/python2.6/multiprocessing/process.py"、43行目
    _掃除()
  _cleanupのファイル"/usr/local/lib/python2.6/multiprocessing/process.py"、53行目
    p._popen.poll()がNoneでない場合:
  ファイル"/usr/local/lib/python2.6/multiprocessing/forking.py"、行106、ポーリング
    pid、sts = os.waitpid(self.pid、flag)
OSError:[Errno10]子プロセスがありません

デーモンプロセス(親)は、多数のプロセス(子)を生成し、定期的にプロセスをポーリングして、プロセスが完了したかどうかを確認します。親は、プロセスの1つが完了したことを検出すると、そのプロセスを再開しようとします。この時点で、上記の例外が発生します。プロセスの1つが完了すると、マルチプロセッシングモジュールを含むすべての操作でこの例外が生成されるようです。デーモン以外のPythonスクリプトで同じコードを実行すると、エラーなしで実行されます。

編集:

サンプルスクリプト

from daemon import runner

class DaemonApp(object):
    def __init__(self, pidfile_path, run):
        self.pidfile_path = pidfile_path
        self.run = run

        self.stdin_path = '/dev/null'
        self.stdout_path = '/dev/tty'
        self.stderr_path = '/dev/tty'

def run():
    import multiprocessing as processing
    import time
    import os
    import sys
    import signal

    def func():
        print 'pid: ', os.getpid()
        for i in range(5):
            print i
            time.sleep(1)

    process = processing.Process(target=func)
    process.start()

    while True:
        print 'checking process'
        if not process.is_alive():
            print 'process dead'
            process = processing.Process(target=func)
            process.start()
        time.sleep(1)

# uncomment to run as daemon
app = DaemonApp('/root/bugtest.pid', run)
daemon_runner = runner.DaemonRunner(app)
daemon_runner.do_action()

#uncomment to run as regular script
#run()
4

6 に答える 6

6

問題は、デーモンとマルチプロセッシングモジュール間の競合、特にSIGCLD(子プロセス終了)信号の処理です。デーモンは起動時にSIGCLDをSIG_IGNに設定します。これにより、少なくともLinuxでは、終了した子がすぐに刈り取られます(親がwait()を呼び出すまでゾンビになるのではありません)。ただし、マルチプロセッシングのis_aliveテストはwait()を呼び出して、プロセスが生きているかどうかを確認します。プロセスがすでに刈り取られている場合は失敗します。

最も簡単な解決策は、SIGCLDをSIG_DFLに戻すことです(デフォルトの動作-シグナルを無視し、親が終了した子プロセスを待機するようにします):

def run():
    # ...

    signal.signal(signal.SIGCLD, signal.SIG_DFL)

    process = processing.Process(target=func)
    process.start()

    while True:
        # ...
于 2009-09-16T08:24:54.183 に答える
4

モジュールのバグが原因で、無視するとモジュールにSIGCLD問題が発生します(問題1731717 、2011年9月21日現在も開いています)。subprocess

この動作は、ライブラリのバージョン1.4.8で対処されています。python-daemonこれで、デフォルトのいじりが省略されるSIGCLDため、他の標準ライブラリモジュールとのこの不快な相互作用がなくなります。

于 2009-09-17T15:45:43.063 に答える
0

少し前にtrunkと2.6maintに修正が加えられたと思います。これは、これに役立つはずです。python-trunkまたは最新の2.6-maintsvnでスクリプトを実行してみてください。バグ情報を取得できません

于 2009-09-01T01:01:06.130 に答える
0

エラーはプロセスの最後に発生しているようです。手がかりはトレースバックの最初にあります。引用します...:

File "/usr/local/lib/python2.6/atexit.py", line 24, in _run_exitfuncs
    func(*targs, **kargs)

が実行されている場合atexit._run_exitfuncs、これは自分のプロセスが終了していることを明確に示しています。したがって、エラー自体はある意味で小さな問題です。multiprocessingモジュールがプロセスから「終了時」に実行するように登録した関数からだけです。本当に興味深い問題は、なぜメインプロセスが終了するのかということです。これは、キャッチされていない例外が原因である可能性があります。マルチプロセッシングが出口で実行するために登録されているものが何であれ、他の例外によって失われる前に、例外フックを設定して豊富な診断情報を表示してみてください...

于 2009-09-01T03:24:06.607 に答える
0

Python2.6を搭載したRHEL5.3でセロリ分散タスクマネージャーを使用しているときにも、これに遭遇しています。私のトレースバックは少し異なって見えますが、エラーは同じです:

      File "/usr/local/lib/python2.6/multiprocessing/pool.py", line 334, in terminate
    self._terminate()
  File "/usr/local/lib/python2.6/multiprocessing/util.py", line 174, in __call__
    res = self._callback(*self._args, **self._kwargs)
  File "/usr/local/lib/python2.6/multiprocessing/pool.py", line 373, in _terminate_pool
    p.terminate()
  File "/usr/local/lib/python2.6/multiprocessing/process.py", line 111, in terminate
    self._popen.terminate()
  File "/usr/local/lib/python2.6/multiprocessing/forking.py", line 136, in terminate
    if self.wait(timeout=0.1) is None:
  File "/usr/local/lib/python2.6/multiprocessing/forking.py", line 121, in wait
    res = self.poll()
  File "/usr/local/lib/python2.6/multiprocessing/forking.py", line 106, in poll
    pid, sts = os.waitpid(self.pid, flag)
OSError: [Errno 10] No child processes

かなりイライラします。私は今pdbを介してコードを実行していますが、まだ何も発見していません。

于 2009-09-14T06:25:02.973 に答える
0

元のサンプルスクリプトには「importsignal」がありますが、signalは使用されていません。ただし、このエラーメッセージの原因となるスクリプトがあり、それは信号処理が原因であったため、他の人に何が起こっているのかをここで説明します。シグナルハンドラー内で、私はプロセスを使って何かをしていました(たとえば、新しいプロセスの作成)。どうやらこれは機能しないので、ハンドラー内でそれをやめ、エラーを修正しました。(注:sleep()関数はシグナル処理後にウェイクアップするため、プロセスで処理を行う必要がある場合は、シグナルに基づいて動作するための代替アプローチになります)

于 2009-09-14T20:20:25.107 に答える