python多进程编程之进程池中实现ctrl c让所有进程结束并正常退出

       python多进程编程中,一般通过标准库multiprocessing实现,对此,既可以通过Process类实现,也可以通过进程池Pool实现。本文解决的问题是针对Pool的,因为只有在使用进程池时才会出现ctrl c无法正常退出程序,而使用Process类实现时ctrl c可以中止程序并退出。

       在python的多进程编程中,有时候当程序正在执行的时候,我们希望通过ctrl c直接中止程序的执行并正常退出程序,但是在使用Pool的时候,是无法直接退出的。实际上ctrl c之后,子进程接收到这个信号,会中止运行,但是主进程会被阻塞,无法正常退出,具体原因可能是主进程需要等到所有子进程的返回正常运行结果后才会继续执行主进程中的逻辑,但是若子进程是被中断的,则主进程便无法接收到子进程的运行结果,从而会一直阻塞,而且主进程阻塞时也不会接收到ctrl c的中断信号,这样就会导致程序一直卡住,从而无法退出,除非强制杀掉主进程。

       这里的‘子进程返回正常的运行结果’实际上就是需要程序正常的运行结束,而不能被中断,但是这其实是算一个python多进程编程的Pool中的一个小bug,因为就算被中断,也应该返回一个结果给主进程,而不是让主进程一直被阻塞。要解决这个问题,实际上我们只要在子进程的执行语句中,加入一个异常捕捉就好。因为ctrl c实际上会给程序抛出一个KeyboardInterrupt异常,所以我们只需要在目标函数的代码中加入try...except KeyboardInterrupt...即可,这样当我们ctrl c的时候,子进程会捕捉到这个异常,然后会正常的退出并把结果传给主进程,从而不会让主进程一直阻塞。

       但是要让主进程正常退出,在Unix系统下,其实只要在目标函数的代码中加入KeyboardInterrupt的异常捕捉就够了,这样主进程接收到所有子进程的结果后,会进一步执行下面的语句,然后退出;但是在Windows系统下,这样还是不够的,主进程会进一步执行接下来的语句,但是执行完后并不会正常退出,至于具体原因笔者还不是特别的清楚,希望清楚的读者可以给笔者留言。

       所以在Windows系统下,仅仅加入异常捕捉是不够的,还需要在主进程的代码中实现强制杀死主进程的语句,这个可以通过os.popen函数实现,命令为os.popen('taskkill.exe /f /pid:%d'%pid),其中/f表示强制杀死后面的进程id。具体代码如下。

from multiprocessing import Process,Pool
import os,time


def f():
   
    '''
    # 该代码块在unix和windows下均无法正常返回结果,主进程会一直被阻塞
    pid=os.getpid()
    print('pid:%d'%pid)
    time.sleep(10)
    '''
    
    # 如下代码中加入异常捕捉后可以正常返回结果,防止主进程一直被阻塞
    pid=os.getpid()
    try:
        print('pid:%d'%pid)
        time.sleep(10)
    except KeyboardInterrupt:
        print('进程%d被中断...'%pid)
        
        
if __name__=='__main__':
    
    pool=Pool(2)
    print('ppid:%d'%os.getpid())
    try:
        
        res=[pool.apply_async(f,) for x in range(2)]
        pool.close()
        pool.join()
    except KeyboardInterrupt:
        print('catch keyboardinterupterror')
        pid=os.getpid()
        os.popen('taskkill.exe /f /pid:%d'%pid) #在unix下无需此命令,但在windows下需要此命令强制退出当前进程
    except Exception as e:
        print(e)
    else:
        print('quit normally')

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值