2013-05-06 12 views
8

私はレンダリングを行っています。クライアントが新しいコマンドを受け取れるように、レンダリングの複数のインスタンスをブロックすることなくクライアントを起動する必要があります。私は正しく動作しているが、私は作成されたプロセスを終了するのに問題があります。グローバルレベルでPythonマルチプロセッシングプールが終了する

(私は任意の関数からアクセスできるように)、私は私のプールを定義します。

p = Pool(2) 

私はその後、apply_asyncと私のレンダラを呼び出します。仕上げに機能

for i in range(totalInstances): 
    p.apply_async(render, (allRenderArgs[i],args[2]), callback=renderFinished) 
p.close() 

バックグラウンドでプロセスを起動し、新しいコマンドを待ちます。 (それがエラーを印刷し)、Pythonの終了が、バックグラウンド・プロセスが残っている

def close(): 
'close this client instance' 
tn.write ("say "+USER+" is leaving the farm\r\n") 
try: 
    p.terminate() 
except Exception,e: 
    print str(e) 
    sys.exit() 
sys.exit() 

エラーを与えていないようです:私はクライアントを殺し、レンダリングを停止します簡単なコマンドを作りましたランニング。誰もがこれらの起動プログラムを制御する良い方法をお勧めしますか?

+0

'from multiprocessing import util;でデバッグログを有効にしてください。 util.get_logger()。setLevel(util.DEBUG) 'を実行し、出力を貼り付けます。 – schlamar

+2

これまでのような振る舞いを見たことがありますが、今は再現できません... p.join()を呼び出すとp.terminate()を呼び出した後に役立つのだろうか?また、終了を呼び出す必要がある場合でも、sys.exit()を実行するだけでプールとそのプロセスすべてが適切にガベージコレクトされるかどうかは疑問です。 – mdscruggs

+0

ロギングを有効にしようとすると、コンソールでこれが表示されます:「ロガーのマルチプロセッシングでハンドラが見つかりませんでした」残念ながら、p.terminate()の後にp.join() .exit()はPythonを閉じますが、プロセスをバックグラウンドで実行します。 – tk421storm

答えて

-4

私自身の質問に対する回答が見つかりました。第一の問題は、関数ではなくサードパーティのアプリケーションを呼び出すことでした。サブプロセス[call()またはPopen()を使用して)を呼び出すと、新しいアプリケーションを呼び出すことのみを目的とするpythonの新しいインスタンスが作成されます。しかし、Pythonが終了すると、Pythonのこの新しいインスタンスが終了し、アプリケーションは実行されたままになります。

解決策は、作成されたpythonプロセスのpidを見つけて、そのpidの子を取得し、それらを強制終了することです。このコードはosxに固有です。 Linuxで利用可能な(grepに依存しない)より簡単なコードがあります。

for process in pool: 
    processId = process.pid 
    print "attempting to terminate "+str(processId) 
    command = " ps -o pid,ppid -ax | grep "+str(processId)+" | cut -f 1 -d \" \" | tail -1" 
    ps_command = Popen(command, shell=True, stdout=PIPE) 
    ps_output = ps_command.stdout.read() 
    retcode = ps_command.wait() 
    assert retcode == 0, "ps command returned %d" % retcode 
    print "child process pid: "+ str(ps_output) 
    os.kill(int(ps_output), signal.SIGTERM) 
    os.kill(int(processId), signal.SIGTERM) 
5

まだこの問題が発生している場合は、Pooldaemonic processesとシミュレートしてみてください(デーモン以外のプロセスからプール/プロセスを開始すると仮定します)。あなたのPoolプロセスが終了するはずだと思われるので、これが最善の解決策であるとは思えませんが、これは私が思いつくことができるすべてです。あなたのコールバックが何をするのかわからないので、私は下の私の例でそれをどこに置くべきか分かりません。

__main__にあなたのPoolを作成しようとすると、プロセスがグローバルに生成されたときに奇妙なことが発生していることがわかりました。これは、Windowsの場合に特に当てはまります。http://docs.python.org/2/library/multiprocessing.html#windows

from multiprocessing import Process, JoinableQueue 

# the function for each process in our pool 
def pool_func(q): 
    while True: 
     allRenderArg, otherArg = q.get() # blocks until the queue has an item 
     try: 
      render(allRenderArg, otherArg) 
     finally: q.task_done() 

# best practice to go through main for multiprocessing 
if __name__=='__main__': 
    # create the pool 
    pool_size = 2 
    pool = [] 
    q = JoinableQueue() 
    for x in range(pool_size): 
     pool.append(Process(target=pool_func, args=(q,))) 

    # start the pool, making it "daemonic" (the pool should exit when this proc exits) 
    for p in pool: 
     p.daemon = True 
     p.start() 

    # submit jobs to the queue 
    for i in range(totalInstances): 
     q.put((allRenderArgs[i], args[2])) 

    # wait for all tasks to complete, then exit 
    q.join() 
+1

興味深い!グローバルではなくメインで定義することについての素晴らしいヒント。私はこの方法で再構築し、それは私の問題を解決しませんでした(下記参照)が、私はより良い建設が好きです。ありがとう! – tk421storm

5

私は解決策を見つけた:

def close_pool(): 
    global pool 
    pool.close() 
    pool.terminate() 
    pool.join() 

def term(*args,**kwargs): 
    sys.stderr.write('\nStopping...') 
    # httpd.shutdown() 
    stophttp = threading.Thread(target=httpd.shutdown) 
    stophttp.start() 
    stoppool=threading.Thread(target=close_pool) 
    stoppool.daemon=True 
    stoppool.start() 


signal.signal(signal.SIGTERM, term) 
signal.signal(signal.SIGINT, term) 
signal.signal(signal.SIGQUIT, term) 

は罰金作品といつも私がテストした:このように、別のスレッドのプールを停止します。

関連する問題