web-dev-qa-db-ja.com

python multiprocessing pool terminate

私はレンダーファームで作業しています。クライアントが新しいコマンドを受信できるように、ブロックせずにレンダラーの複数のインスタンスを起動できるようにする必要があります。正しく機能していますが、作成したプロセスを終了できません。

グローバルレベルで、プールを定義します(どの関数からでもアクセスできるようにします)。

p = Pool(2)

次に、apply_asyncを使用してレンダラーを呼び出します。

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

その関数は終了し、プロセスをバックグラウンドで起動し、新しいコマンドを待ちます。クライアントを終了してレンダリングを停止する簡単なコマンドを作成しました。

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()

エラーは表示されないようです(エラーが出力されます)、pythonは終了しますが、バックグラウンドプロセスはまだ実行中です。これらの起動されたプログラムを制御するより良い方法を誰かが推奨できますか?

12
tk421storm

私は解決策を見つけました:次のように別のスレッドでプールを停止します:

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)

正常に動作し、常にテストしました。

7
eri

それでもこの問題が発生する場合は、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()
5
mdscruggs
# -*- coding:utf-8 -*-
import multiprocessing
import time
import sys
import threading
from functools import partial


#> work func
def f(a,b,c,d,e):
    print('start')
    time.sleep(4)
    print(a,b,c,d,e)

###########> subProcess func
#1. start a thead for work func
#2. waiting thead with a timeout
#3. exit the subProcess
###########
def mulPro(f, *args, **kwargs):
    timeout = kwargs.get('timeout',None)

    #1. 
    t = threading.Thread(target=f, args=args)
    t.setDaemon(True)
    t.start()
    #2. 
    t.join(timeout)
    #3. 
    sys.exit()

if __name__ == "__main__":

    p = multiprocessing.Pool(5)
    for i in range(5):
        #1. process the work func with "subProcess func"
        new_f = partial(mulPro, f, timeout=8)
        #2. fire on
        p.apply_async(new_f, args=(1,2,3,4,5),)

        # p.apply_async(f, args=(1,2,3,4,5), timeout=2)
    for i in range(10):
        time.sleep(1)
        print(i+1,"s")

    p.close()
    # p.join()
0
rodemon