0

スクリプトで python 2.7.3 とデーモン ランナーを使用しています。run(loop) メソッドでは、しばらくスリープしたいのですが、そのようなコードではありません:

while True:
    time.sleep(10)

multiprocessing.Event などの同期プリミティブを待機したい。私のコードがあります:

# -*- coding: utf-8 -*-
import logging
from daemon import runner
import signal
import multiprocessing

import spyder_cfg

logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', datefmt='%m-%d %H:%M', filename=spyder_cfg.log_file)

class Daemon(object):     
    def __init__(self, pidfile_path):
        self.stdin_path = '/dev/null'
        self.stdout_path = '/dev/tty'
        self.stderr_path = '/dev/tty'
        self.pidfile_path = None
        self.pidfile_timeout = 5
        self.pidfile_path = pidfile_path 

    def setup_daemon_context(self, daemon_context):
        self.daemon_context = daemon_context

    def run(self):
        logging.info('Spyder service has started')
        logging.debug('event from the run() = {}'.format(self.daemon_context.stop_event))
        while not self.daemon_context.stop_event.wait(10):
            try:
                logging.info('Spyder is working...')
            except BaseException as exc:
                logging.exception(exc)
        logging.info('Spyder service has been stopped') 

    def handle_exit(self, signum, frame):
        try:
            logging.info('Spyder stopping...')
            self.daemon_context.stop_event.set()
        except BaseException as exc:
            logging.exception(exc)

if __name__ == '__main__':
    app = Daemon(spyder_cfg.pid_file)
    d = runner.DaemonRunner(app)
    d.daemon_context.working_directory = spyder_cfg.work_dir
    d.daemon_context.files_preserve = [h.stream for h in logging.root.handlers]
    d.daemon_context.signal_map = {signal.SIGUSR1: app.handle_exit} 
    d.daemon_context.stop_event = multiprocessing.Event()
    app.setup_daemon_context(d.daemon_context)
    logging.debug('event from the main = {}'.format(d.daemon_context.stop_event))
    d.do_action()

それは私のログファイルの記録です:

06-04 11:32 root         DEBUG    event from the main = <multiprocessing.synchronize.Event object at 0x7f0ef0930d50>
06-04 11:32 root         INFO     Spyder service has started
06-04 11:32 root         DEBUG    event from the run() = <multiprocessing.synchronize.Event object at 0x7f0ef0930d50>
06-04 11:32 root         INFO     Spyder is working...
06-04 11:32 root         INFO     Spyder stopping...

ログに「Spyder サービスが停止しました」というメッセージが表示されず、プログラムが set() 呼び出しでハングします。デバッグ中に、Event.set() 呼び出し時にハングすることがわかります。待機しているすべてのエンティティがウェイクアップしている間、set メソッドがセマフォでハングします。Event がグローバル オブジェクトまたは threading.Event になる理由はありません。私はこの1つの答えを見ますが、それは私にとっては良くありません。multiprocessing.Event と同じ動作をするタイムアウト待機による待機の代替手段はありますか?

4

1 に答える 1

0

シグナルハンドラーからスタックを出力しますが、デッドロックがあると思います。シグナルハンドラーはメインプロセスと同じスタックを使用し、Event.set() を呼び出すと、メソッド wait() がスタックの上位にあるためです...

def handle_exit(self, signum, frame):
    try:
        logging.debug('Signal handler:{}'.format(traceback.print_stack()))
    except BaseException as exc:
        logging.exception(exc)


d.do_action()
  File ".../venv/work/local/lib/python2.7/site-packages/daemon/runner.py", line 189, in do_action
    func(self)
  File ".../venv/work/local/lib/python2.7/site-packages/daemon/runner.py", line 134, in _start
    self.app.run()
  File ".../venv/work/skelet/src/spyder.py", line 32, in run
    while not self.daemon_context.stop_event.wait(10):
  File "/usr/lib/python2.7/multiprocessing/synchronize.py", line 337, in wait
    self._cond.wait(timeout)
  File "/usr/lib/python2.7/multiprocessing/synchronize.py", line 246, in wait
    self._wait_semaphore.acquire(True, timeout)
  File ".../venv/work/skelet/src/spyder.py", line 41, in handle_exit
    logging.debug('Signal handler:{}'.format(traceback.print_stack()))

そのため、この修正により問題が解決されます。

def handle_exit(self, signum, frame):  
    t = Timer(1, self.handle_exit2)  
    t.start()

def handle_exit2(self): 
    self.daemon_context.stop_event.set()
于 2014-06-04T12:17:33.130 に答える