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

Python multiprocessing: Kill producer and consumer processes with 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 传递给客户和生产者流程的原因?

根据 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 语句。