捉按Ctrl + C / SIGINT和出口multiprocesses摆好在python(Catc

2019-06-26 00:07发布

如何赶上多进程Python程序中按Ctrl + C,退出所有流程摆好,我需要的解决方案,以UNIX和Windows的工作都。 我已经试过如下:

import multiprocessing
import time
import signal
import sys

jobs = []

def worker():
    signal.signal(signal.SIGINT, signal_handler)
    while(True):
        time.sleep(1.1234)
        print "Working..."

def signal_handler(signal, frame):
    print 'You pressed Ctrl+C!'
    # for p in jobs:
    #     p.terminate()
    sys.exit(0)

if __name__ == "__main__":
    for i in range(50):
        p = multiprocessing.Process(target=worker)
        jobs.append(p)
        p.start()

而且它是一种工作的,但我不认为这是正确的解决方案。

编辑:这可能是一个重复的这一个

Answer 1:

以前接受的解决方案具有竞争条件,它不与工作mapasync功能。

处理按Ctrl + C /正确的方法SIGINTmultiprocessing.Pool是:

  1. 制作过程中忽略SIGINT程序才能Pool被创建。 通过这种方式创建的子进程继承SIGINT处理程序。
  2. 恢复原来的SIGINT父进程处理程序后, Pool已创建。
  3. 使用map_asyncapply_async而不是阻塞mapapply
  4. 等待与超时的结果,因为默认阻塞等待忽略所有的信号。 这是Python的错误https://bugs.python.org/issue8296 。

把它放在一起:

#!/bin/env python
from __future__ import print_function

import multiprocessing
import os
import signal
import time

def run_worker(delay):
    print("In a worker process", os.getpid())
    time.sleep(delay)

def main():
    print("Initializng 2 workers")
    original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
    pool = multiprocessing.Pool(2)
    signal.signal(signal.SIGINT, original_sigint_handler)
    try:
        print("Starting 2 jobs of 5 seconds each")
        res = pool.map_async(run_worker, [5, 5])
        print("Waiting for results")
        res.get(60) # Without the timeout this blocking call ignores all signals.
    except KeyboardInterrupt:
        print("Caught KeyboardInterrupt, terminating workers")
        pool.terminate()
    else:
        print("Normal termination")
        pool.close()
    pool.join()

if __name__ == "__main__":
    main()

正如@YakovShklarov指出,存在的时间忽略的信号,并在父进程,在此期间,可以将信号丢失它取消忽略之间的窗口。 使用pthread_sigmask代替暂时阻止信号的在父进程的递送会防止丢失的信号,然而,它不提供在Python-2。



Answer 2:

该解决方案基于此链接和该链接并解决了这个问题,我不得不搬到Pool虽然:

import multiprocessing
import time
import signal
import sys

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

def worker():
    while(True):
        time.sleep(1.1234)
        print "Working..."

if __name__ == "__main__":
    pool = multiprocessing.Pool(50, init_worker)
    try:
        for i in range(50):
            pool.apply_async(worker)

        time.sleep(10)
        pool.close()
        pool.join()

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


Answer 3:

只是在处理你的工作进程中一个KeyboardInterrupt,SystemExit例外:

def worker():
    while(True):
        try:
            msg = self.msg_queue.get()
        except (KeyboardInterrupt, SystemExit):
            print("Exiting...")
            break


文章来源: Catch Ctrl+C / SIGINT and exit multiprocesses gracefully in python