Python多处理:使用KeyboardInterrupt杀死生产者和消费者进程

时间:2017-06-16 08:24:33

标签: python python-2.7 multiprocessing keyboardinterrupt

如果执行键盘快捷键CTRL+C,我希望客户和生产者进程在以下python脚本中停止。但是进程不会停止 - 键盘中断不会传递给它们。此外,永远不会输入主进程的except块。

import time
import multiprocessing as mp
from multiprocessing.managers import SyncManager
import signal

class Consumer(mp.Process):
    def __init__(self, **kwargs):
        mp.Process.__init__(self, **kwargs)

    def run(self):
        proc_name = self.name
        try:
            while True:
                print("{}".format(proc_name))
                time.sleep(3)
        except KeyboardInterrupt:
            print("{} stopped".format(proc_name)) # never printed
        return

class Producer(mp.Process):
    def __init__(self, **kwargs):
        mp.Process.__init__(self, **kwargs)

    def run(self):
        try:
            while True:
                time.sleep(3)
                print("Producer here.")
        except KeyboardInterrupt:
            print("Producer stopped.") # never printed
        return

def main():
    def __init_worker():
        signal.signal(signal.SIGINT, signal.SIG_IGN)
        print('init') # not printed!!??

#    manager = SyncManager() # does not change anything
#    manager.start(__init_worker)

    consumers = [Consumer(target=__init_worker) for i in xrange(3)]
    producer = Producer(target=__init_worker)

    producer.daemon = True # does not change anything
    producer.start()
    for c in consumers:
        c.daemon = True
        c.start()

    try:
        producer.join()
        for c in consumers:
            c.join()
    except Exception as e:
        print('STOP') # never printed
        raise e

if __name__ == '__main__':
    main()

通过对客户使用multiprocesing.Pool并让主进程作为生产者工作,我的任务可能还有一个解决方案,但我想知道为什么我的实现不能按原样实现我需要调整。

我意识到__init_worker似乎没有被执行(如果它位于main之外则没有区别)。也许是没有将KeyboardInterrupt传递给客户和生产者流程的原因?

1 个答案:

答案 0 :(得分:3)

根据eryksun的评论,我改进了我的代码并立即使用multiprocessing.Event。而且脚本现在正如预期的那样工作。我也删除了一些我认为不再需要的行。由于我在搜索网络时没有找到任何类似的解决方案,因此我的代码来了:

import time
import multiprocessing as mp

class Consumer(mp.Process):
    def __init__(self, quit_event, **kwargs):
        mp.Process.__init__(self, **kwargs)
        self.quit_event = quit_event

    def run(self):
        proc_name = self.name
        while not self.quit_event.is_set():
            print("{}".format(proc_name))
            time.sleep(3)
        print("{} stopped".format(proc_name))
        return

class Producer(mp.Process):
    def __init__(self, quit_event, **kwargs):
        mp.Process.__init__(self, **kwargs)
        self.quit_event = quit_event

    def run(self):
        while not self.quit_event.is_set():
            print("Producer here.")
            time.sleep(3)
        print("Producer stopped")
        return


def main():
    quit_event = mp.Event()

    consumers = [Consumer(quit_event) for i in xrange(3)]
    producer = Producer(quit_event)

    producer.start()
    for c in consumers:
        c.start()

    try:
        producer.join()
        for c in consumers:
            c.join()
    except KeyboardInterrupt as e:
        print('\nSTOP')
        quit_event.set()
    except Exception as e:
        quit_event.set()
        raise e
    finally:
        producer.terminate()
        producer.join()
        for c in consumers:
            c.terminate()
            c.join()

if __name__ == '__main__':
    main()

希望,这有助于某人。

修改:转发terminatejoin语句。