python多处理池终止

tk4*_*orm 10 python pool multiprocessing

我正在使用renderfarm,我需要我的客户端能够启动渲染器的多个实例,而不会阻塞,因此客户端可以接收新的命令.我已经正常工作,但是我无法终止创建的进程.

在全局级别,我定义了我的池(以便我可以从任何函数访问它):

p = Pool(2)
Run Code Online (Sandbox Code Playgroud)

然后我用apply_async调用我的渲染器:

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

该函数完成,在后台启动进程,并等待新命令.我做了一个简单的命令,将杀死客户端并停止渲染:

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()
Run Code Online (Sandbox Code Playgroud)

它似乎没有给出错误(它会打印错误),python终止但后台进程仍在运行.任何人都可以推荐更好的方法来控制这些推出的程序吗

eri*_*eri 7

我找到了解决方案:在单独的线程中停止池,如下所示:

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)
Run Code Online (Sandbox Code Playgroud)

工作正常,我经常测试.

  • 它用于中断“ctrl+c”、任务终止、sys.exit() 等。 (2认同)

mds*_*ggs 5

如果您仍然遇到此问题,可以尝试Pool使用守护进程模拟(假设您从非守护进程启动池/进程).我怀疑这是最好的解决方案,因为看起来你的Pool进程应该退出,但这就是我能想到的.我不知道你的回调是做什么的,所以我不知道在下面的例子里把它放在哪里.

我还建议尝试创建你的Poolin,__main__因为我的经验(和文档)在全局生成进程时会出现奇怪现象.如果您使用的是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()
Run Code Online (Sandbox Code Playgroud)


tk4*_*orm -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)
Run Code Online (Sandbox Code Playgroud)