• multiprocessing 让子进程忽略信号,手动关闭子进程


    起因

    同事想要写一个代码,主进程中监听SIGINT、SIGTERM信号退出,并关闭启动的子进程,代码类似这样

    import signal
    import sys
    import time
    from multiprocessing import Process
    from multiprocessing import Manager
    
    
    class Test:
    
        def __init__(self):
            self.is_running = True
            if sys.platform != 'win32':
                signal.signal(signal.SIGHUP, self._signal_handler)
            signal.signal(signal.SIGINT, self._signal_handler)
            signal.signal(signal.SIGTERM, self._signal_handler)
    
        def _signal_handler(self, signum, frame):
            """
            Terminate scenario ticking when receiving a signal interrupt
            """
            self.is_running = False
            print('关闭场景调度')
    
        def listen_manage(self, running, kill_task_lst):
            """监控取消任务"""
            while running.value:
                kill_task_lst.append(1)
                time.sleep(1)
                print("child is running")
    
        def run(self):
            """启动场景调度"""
            kill_task_lst = Manager().list()
            running = Manager().Value(bool, True)
            print('启动监控进程')
            p = Process(target=self.listen_manage, args=(running, kill_task_lst, ))
            p.start()
            while self.is_running:
                time.sleep(0.5)
                print("main is running")
    

    但是发现在ctrl + c 时候,子进程也同时接收到了信号,退出了

    启动监控进程
    main is running
    main is running
    child is running
    main is running
    关闭场景调度
    Process Process-3:
    Traceback (most recent call last):
      File "D:\software\anaconda\envs\test_egg1\lib\multiprocessing\process.py", line 315, in _bootstrap
        self.run()
      File "D:\software\anaconda\envs\test_egg1\lib\multiprocessing\process.py", line 108, in run
        self._target(*self._args, **self._kwargs)
      File "D:\python_projects\pythonProject\test_egg\test.py", line 35, in listen_manage
        time.sleep(1)
    KeyboardInterrupt
    main is running
    

    这时猜想到可能是子进程也监听了SIGINT,退出了程序,所以想在子任务中设置忽略信号,改造后的 listen_manage:

        def listen_manage(self, running, kill_task_lst):
            """监控取消任务"""
            if sys.platform != 'win32':
                signal.signal(signal.SIGHUP, signal.SIG_IGN)
            signal.signal(signal.SIGINT, signal.SIG_IGN)
            signal.signal(signal.SIGTERM, signal.SIG_IGN)
            while running.value::
                kill_task_lst.append(1)
                time.sleep(1)
                print("child is running")
    

    运行后会报 BrokenPipeError: [WinError 232] 管道正在被关闭。

    启动监控进程
    main is running
    main is running
    child is running
    main is running
    关闭场景调度
    main is running
    child is running
    Process Process-4:
    Traceback (most recent call last):
      File "D:\software\anaconda\envs\test_egg1\lib\multiprocessing\process.py", line 315, in _bootstrap
        self.run()
      File "D:\software\anaconda\envs\test_egg1\lib\multiprocessing\process.py", line 108, in run
        self._target(*self._args, **self._kwargs)
      File "D:\python_projects\pythonProject\test_egg\test.py", line 37, in listen_manage
        kill_task_lst.append(1)
      File "", line 2, in append
      File "D:\software\anaconda\envs\test_egg1\lib\multiprocessing\managers.py", line 834, in _callmethod
        conn.send((self._id, methodname, args, kwds))
      File "D:\software\anaconda\envs\test_egg1\lib\multiprocessing\connection.py", line 206, in send
        self._send_bytes(_ForkingPickler.dumps(obj))
      File "D:\software\anaconda\envs\test_egg1\lib\multiprocessing\connection.py", line 280, in _send_bytes
        ov, err = _winapi.WriteFile(self._handle, buf, overlapped=True)
    BrokenPipeError: [WinError 232] 管道正在被关闭。
    

    这里想到的原因是父进程直接退出了,导致共享变量kill_task_lst被关闭导致的,所以想在关闭管道前等待子进程退出
    可执行的完整代码:

    import signal
    import sys
    import time
    from multiprocessing import Process
    from multiprocessing import Manager
    
    
    class Test:
    
        def __init__(self):
            self.is_running = True
            if sys.platform != 'win32':
                signal.signal(signal.SIGHUP, self._signal_handler)
            signal.signal(signal.SIGINT, self._signal_handler)
            signal.signal(signal.SIGTERM, self._signal_handler)
    
        def _signal_handler(self, signum, frame):
            """
            Terminate scenario ticking when receiving a signal interrupt
            """
            self.is_running = False
            print('关闭场景调度')
    
        def listen_manage(self, running, kill_task_lst):
            """监控取消任务"""
            if sys.platform != 'win32':
                signal.signal(signal.SIGHUP, signal.SIG_IGN)
            signal.signal(signal.SIGINT, signal.SIG_IGN)
            signal.signal(signal.SIGTERM, signal.SIG_IGN)
            while running.value:
                kill_task_lst.append(1)
                time.sleep(1)
                print("child is running")
    
        def run(self):
            """启动场景调度"""
            kill_task_lst = Manager().list()
            running = Manager().Value(bool, True)
            print('启动监控进程')
            p = Process(target=self.listen_manage, args=(running, kill_task_lst, ))
            p.start()
            while self.is_running:
                time.sleep(0.5)
                print("main is running")
            running.set(False)
            while p.is_alive():
                time.sleep(0.01)
            print("finish.....")
    
    if __name__ == '__main__':
        t = Test()
        t.run()
    

    执行结果:

    启动监控进程
    main is running
    main is running
    child is running
    main is running
    关闭场景调度
    main is running
    child is running
    finish.....
    
  • 相关阅读:
    R语言用logistic逻辑回归和AFRIMA、ARIMA时间序列模型预测世界人口
    数据化管理洞悉零售及电子商务——零售策略中的数据化管理
    410. 分割数组的最大值
    vue使用pdf 导出当前页面,(jspdf, html2canvas )
    java基于ssm+vue的婚纱摄影网站
    Optional的应用
    JavaEE:CentOS 7中安装Nacos
    shell学习笔记
    React高级特性之HOC高阶组件
    【软件工程_设计模式】——为什么要使用设计模式?
  • 原文地址:https://www.cnblogs.com/luslin/p/16658272.html