管理和终止任何进程的可靠方法

时间:2019-02-04 18:15:33

标签: python python-multiprocessing

我正在编写代码以并行运行实验。我无法控制实验的工作,它们可能会使用subprocess.Popencheck_output打开来运行一个或多个其他子进程。

我有两个条件:我希望能够杀死超过超时的实验,并且希望杀死KeyboardInterrupt上的实验。

大多数终止进程的方法不能确保杀死所有子进程等。如果一个接一个地运行数百个实验,但是它们都生成了子进程,这些子进程在超时发生后仍然处于活动状态,并且据说该实验被终止,那么这显然是一个问题。

我现在处理这个问题的方式包括添加代码以将实验配置存储在数据库中,生成从命令行加载和运行实验的代码,然后通过subprocess.Popen(cmd, shell=True, start_new_session=True)调用这些命令并使用{{ 1}}。

我的主要问题是:通过命令行调用这些实验很麻烦,因此有一种方法可以直接通过os.killpg调用代码并获得与{{1}相同的效果} + multiprocessing.Process(target=fn)超时,start_new_session=True

os.killpg

我张贴了代码的框架,其中详细介绍了通过命令行启动进程并杀死它们的方法。我的方法的这种版本的另一个复杂之处在于,当KeyboardInterrupt到达时,队列已经终止(由于缺少更好的单词),并且无法与监视进程进行通信(哨兵消息永远不会到达)。相反,我不得不求助于将进程ID写入文件并在主进程中读回该文件,以杀死仍在运行的进程。如果您知道解决此队列问题的方法,那么我将很想了解它。

2 个答案:

答案 0 :(得分:5)

我认为问题是您正在存储Subprocess pid来杀死它,而您需要宿主进程pid,并且您使用了signal.SIGINT,我认为应该是signal.SIGTERM。试试这个,而不是这行:

os.killpg(process.pid, signal.SIGINT)

使用此行:

os.killpg(os.getpgid(process.pid), signal.SIGTERM) 

答案 1 :(得分:4)

我想有一种避免这种情况的方法是使用Try catch块。
假设KeyboardInterrupt到达main(),那么您可以尝试以下方法:

def main():
    try:
        <save configs => c_ids>
        queue = manager.Queue()
        process = Process(target=monitor, args=(queue,))
        process.start()

        def clean_exit():
            queue.put("sentinel")
            <terminate pool and monitor process>

        r = pool.map_async(worker, [(c_id, queue) for c_id in c_ids])
        atexit.register(clean_exit)
        r.wait()
        <terminate pool and monitor process>
    except KeyboardInterrupt as e:
        pass
        #write the process you want to keep continuing. 

猜猜这会有所帮助。