首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何终止多进程池进程?

如何终止多进程池进程?
EN

Stack Overflow用户
提问于 2013-05-06 22:34:53
回答 4查看 61.7K关注 0票数 15

我在一个渲染场上工作,我需要我的客户端能够启动渲染器的多个实例,而不会阻塞,这样客户端就可以接收新的命令。我已经让它正常工作了,但是我在终止创建的进程时遇到了问题。

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

代码语言:javascript
复制
p = Pool(2)

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

代码语言:javascript
复制
for i in range(totalInstances):
    p.apply_async(render, (allRenderArgs[i],args[2]), callback=renderFinished)
p.close()

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

代码语言:javascript
复制
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()

它似乎没有给出错误(它将打印错误),python终止,但后台进程仍在运行。有没有人能推荐一个更好的方法来控制这些启动的程序?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-05-14 22:20:51

找到了我自己问题的答案。主要问题是我调用的是第三方应用程序,而不是函数。当我使用call()或Popen()调用子流程时,它会创建一个新的python实例,其唯一目的是调用新的应用程序。但是,当python退出时,它将终止这个新的python实例,并使应用程序继续运行。

解决方案是通过找到所创建的python进程的pid,获取该pid的子进程,并杀死它们,来实现这一点。这段代码是特定于osx的;还有更简单的代码(不依赖于grep)可用于linux。

代码语言:javascript
复制
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)
票数 -4
EN

Stack Overflow用户

发布于 2013-08-07 05:12:22

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

代码语言:javascript
复制
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)

运行得很好,而且我一直在测试。

代码语言:javascript
复制
signal.SIGINT

键盘中断(CTRL + C)。默认操作是引发KeyboardInterrupt。

代码语言:javascript
复制
signal.SIGKILL

杀死信号。它不能被捕获、阻止或忽略。

代码语言:javascript
复制
signal.SIGTERM

终止信号。

代码语言:javascript
复制
signal.SIGQUIT

使用核心转储退出。

票数 9
EN

Stack Overflow用户

发布于 2013-05-09 03:23:11

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

根据我的经验(和文档),我还建议尝试在__main__中创建Pool,因为在全局派生进程时会出现奇怪的情况。如果你在Windows上,这一点尤其正确:http://docs.python.org/2/library/multiprocessing.html#windows

代码语言:javascript
复制
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()
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16401031

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档