2009-06-20 8 views
4

私はいくつかの他の子プロセスを生成するデーモンプログラムを書いています。 stopスクリプトを実行した後、終了する予定のときにメインプロセスが実行を継続します。これは私を本当に混乱させます。デーモンプロセスを終了する際の問題

import daemon, signal 
from multiprocessing import Process, cpu_count, JoinableQueue 
from http import httpserv 
from worker import work 

class Manager: 
    """ 
    This manager starts the http server processes and worker 
    processes, creates the input/output queues that keep the processes 
    work together nicely. 
    """ 
    def __init__(self): 
     self.NUMBER_OF_PROCESSES = cpu_count() 

    def start(self): 
     self.i_queue = JoinableQueue() 
     self.o_queue = JoinableQueue() 

     # Create worker processes 
     self.workers = [Process(target=work, 
           args=(self.i_queue, self.o_queue)) 
         for i in range(self.NUMBER_OF_PROCESSES)] 
     for w in self.workers: 
      w.daemon = True 
      w.start() 

     # Create the http server process 
     self.http = Process(target=httpserv, args=(self.i_queue, self.o_queue)) 
     self.http.daemon = True 
     self.http.start() 

     # Keep the current process from returning 
     self.running = True 
     while self.running: 
      time.sleep(1) 

    def stop(self): 
     print "quiting ..." 

     # Stop accepting new requests from users 
     os.kill(self.http.pid, signal.SIGINT) 

     # Waiting for all requests in output queue to be delivered 
     self.o_queue.join() 

     # Put sentinel None to input queue to signal worker processes 
     # to terminate 
     self.i_queue.put(None) 
     for w in self.workers: 
      w.join() 
     self.i_queue.join() 

     # Let main process return 
     self.running = False 


import daemon 

manager = Manager() 
context = daemon.DaemonContext() 
context.signal_map = { 
     signal.SIGHUP: lambda signum, frame: manager.stop(), 
     } 

context.open() 
manager.start() 

stopスクリプトはちょうどワンライナーos.kill(pid, signal.SIGHUP)ですが、子供プロセス(ワーカープロセスとhttpサーバ・プロセス)が終了その後うまく、しかしメインプロセスはただそこにとどまり、私が続けるかわかりませんそれが戻ってくるから。

+0

"終了..."と表示されますか? – grieve

+1

私はあなたのコードをそのままデーモンモジュールを除いて試しました。ご使用のバージョンのデーモン・モジュールへのリンクを付けることはできますか? Google検索ではいくつかの選択肢が明らかです。 – grieve

+0

私の遅い応答に申し訳ありません、デーモンモジュールのために私はhttp://pypi.python.org/pypi/python-daemon/ – btw0

答えて

1

私は別の方法を試しましたが、これはうまくいくように思えます(私はそのモジュールがインストールされていないので、コードのデーモン部分を取り出しました)。

import signal 

class Manager: 
    """ 
    This manager starts the http server processes and worker 
    processes, creates the input/output queues that keep the processes 
    work together nicely. 
    """ 
    def __init__(self): 
     self.NUMBER_OF_PROCESSES = cpu_count() 

    def start(self): 

     # all your code minus the loop 

     print "waiting to die" 

     signal.pause() 

    def stop(self): 
     print "quitting ..." 

     # all your code minus self.running 


manager = Manager() 

signal.signal(signal.SIGHUP, lambda signum, frame: manager.stop()) 

manager.start() 

1つの警告として、signal.pause()はシグナルに対してポーズ解除されますので、コードを適宜変更してください。

EDIT:私のためにうまく

次作品:

import daemon 
import signal 
import time 

class Manager: 
    """ 
    This manager starts the http server processes and worker 
    processes, creates the input/output queues that keep the processes 
    work together nicely. 
    """ 
    def __init__(self): 
     self.NUMBER_OF_PROCESSES = 5 

    def start(self): 

     # all your code minus the loop 

     print "waiting to die" 
     self.running = 1 
     while self.running: 
      time.sleep(1) 

     print "quit" 



    def stop(self): 
     print "quitting ..." 

     # all your code minus self.running 

     self.running = 0 


manager = Manager() 

context = daemon.DaemonContext() 
context.signal_map = {signal.SIGHUP : lambda signum, frame: manager.stop()} 

context.open() 
manager.start() 

使用しているのpythonのバージョンは何?

+0

私は手動で信号処理をしません。デーモンモジュールはhttp://pypi.python.org/pypi/python-daemon/ – btw0

1

httpサーバープロセスを作成しますが、join()は作成しません。 httpサーバプロセスを停止するのにos.kill()を実行するのではなく、停止処理のセンチネル(None、あなたがワーカーに送信したのと同じように)を送信してからself.http.join()を実行すればどうなりますか?

更新:あなたはまた、各ワーカーため一度入力キューへNoneセンチネルを送信する必要があります。試してみることができます:

for w in self.workers: 
     self.i_queue.put(None) 
    for w in self.workers: 
     w.join() 

N.B. 2つのループが必要な理由は、join()と同じループでNoneをキューに入れると、w以外のワーカーがそのNoneを受け取る可能性があるため、wに参加すると、呼び出し元がブロックされます。

あなたはworker_honeなどの呼び出しに関してこれらが適切に動作しており、Noneが表示されるとすぐに各作業者が終了することを前提としています(get() -ingなし)。入力キューからそれ以上のもの。

また、少なくともone open, hard-to-reproduce issueにはJoinableQueue.task_done()がありますが、これはあなたを噛んでいる可能性があります。

+0

から処理されています。私のコードで真のループは本当にself.http.joinでした私の変更が反映されたスクリプトの修正版は、少なくとも私の環境では正常終了します。( – btw0

+0

) 。 –

関連する問題