使用PYTHON的多处理池和映射功能进行键盘中断

2022-04-10 00:00:00 python python-multiprocessing

问题描述

我找到了this文章,介绍了如何使用Ctrl+c终止正在运行的多进程代码。以下代码完全正常(可以使用Ctrl+c终止它):

#!/usr/bin/env python

# Copyright (c) 2011 John Reese
# Licensed under the MIT License

import multiprocessing
import os
import signal
import time

def init_worker():
    signal.signal(signal.SIGINT, signal.SIG_IGN)

def run_worker():
    time.sleep(15)

def main():
    print "Initializng 5 workers"
    pool = multiprocessing.Pool(5, init_worker)

    print "Starting 3 jobs of 15 seconds each"
    for i in range(3):
        pool.apply_async(run_worker)

    try:
        print "Waiting 10 seconds"
        time.sleep(10)

    except KeyboardInterrupt:
        print "Caught KeyboardInterrupt, terminating workers"
        pool.terminate()
        pool.join()

    else:
        print "Quitting normally"
        pool.close()
        pool.join()

if __name__ == "__main__":
    main()

问题是我使用多处理模块中的不同函数。我不知道它们与以前的方法有什么不同,它只对我有效(除了这个例子不能使用ctrl+c终止它)。以下是我一直试图根据上面的版本修改的代码(以前的版本没有信号处理,用于在按下ctrl+c时打印回溯):

#!/usr/bin/env python

from time import sleep
import signal
from multiprocessing import Pool
from multiprocessing import cpu_count

def init_worker(n):
  signal.signal(signal.SIGINT, signal.SIG_IGN)
  sleep(.5)
  print "n = %d" % n
  results_sent_back_to_parent = n * n
  return results_sent_back_to_parent

if __name__ == '__main__':
  try:
    p = Pool(processes = cpu_count())
    results = p.map(init_worker, range(50), chunksize = 10)
  except KeyboardInterrupt:
    pool.terminate()
    pool.join()

  print(results)

问题:

  1. 为什么ctrl+c在第一个示例中起作用,而在第二个示例中不起作用
  2. 如何修改ctrl+c将起作用的第二个代码?
  3. 这两个代码有什么不同(我的意思是在多处理环境中,一个使用pool.apply_async,另一个使用map)?

编辑

回复@user2386841

我已在init_worker中添加了signal.signal(signal.SIGINT, signal.SIG_IGN),并尝试在if __name__ == '__main__':之后添加,但id不起作用,与我将其添加为try:块中的最后一行时相同

回复@ThomasWagenaar

它的行为完全相同(我也尝试了上面提到的信号处理程序的不同位置);尽管点击ctr+c,数字仍在打印,唯一可能的终止脚本的方法是使用ctrl+z将其发送到后台,然后使用kill %1

终止

解决方案

我用这个简单的函数解决了这个问题:

import os
import psutil
import signal

parent_id = os.getpid()
def worker_init():
    def sig_int(signal_num, frame):
        print('signal: %s' % signal_num)
        parent = psutil.Process(parent_id)
        for child in parent.children():
            if child.pid != os.getpid():
                print("killing child: %s" % child.pid)
                child.kill()
        print("killing parent: %s" % parent_id)
        parent.kill()
        print("suicide: %s" % os.getpid())
        psutil.Process(os.getpid()).kill()
    signal.signal(signal.SIGINT, sig_int)

我已将其附加到我的池:

Pool(3, worker_init)

ctrl^c后的结果为:

^Csignal: 2
signal: 2
signal: 2
killing child: 14109
killing child: 14110
killing parent: 14104
suicide: 14108
Killed

然后一切都退出

相关文章