键盘中断python的多处理池和映射功能

时间:2015-08-22 19:36:56

标签: python python-multiprocessing

我发现this文章解释了如何使用ctr + 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)?
  4. 修改

    回复@ user2386841

    我在signal.signal(signal.SIGINT, signal.SIG_IGN)评论了init_worker并试图在if __name__ == '__main__':之后添加,但是ID没有用,当我在{{1}中添加它作为最后一行时也一样阻止

    回复@ThomasWagenaar

    它的行为完全相同(我还尝试过如上所述的信号处理程序的各种位置);尽管点击了try:,但数字仍在打印,唯一可能的方法就是使用ctr+c将其发送到后台,然后使用ctrl+z

    进行查杀

2 个答案:

答案 0 :(得分:3)

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

rescue

我把它附在我的游泳池上:

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)

ctrl ^ c之后的结果是:

Pool(3, worker_init)

一切都会退出

答案 1 :(得分:1)

旧线程,但这些示例表现不同的原因是由于众所周知的Python错误(http://bugs.python.org/issue8296,也在this StackOverflow answer中解释)。

你应该完全阅读其他答案以获得完整的想法,但简而言之,问题是底层threading.Condition.wait()调用的行为会有所不同,具体取决于它是否超时。 map()不使用超时,但apply_async()显然确实利用了此超时参数,并且仅当该基础wait()调用超时时才会正确中断。

您应该能够重构代码以使用the Pool docs中指定的异步方法之一。