从multiprocessing源码理解其对SIGINT信号的屏蔽
来源:互联网 发布:易语言写软件 编辑:程序博客网 时间:2024/05/17 23:56
问题引入
由于python
的GIL
(全局解释器锁,Global Interpreter Lock),GIL在任意时刻只运行单个python
线程执行,python
的多线程并不能真正的利用多核CPU,无论有多少个核,程序都职能在一个处理器上运行。
要想利用多核并行计算,就必须使用多进程(直白点讲就是同时运行多个python
程序)。关于多进程,python
自带了multiprocessing
。但在使用中发现,常用的Ctrl+C
结束python
程序的方法对multiprocessing
是不适用的。下面就分析一下这个问题背后的原因。
想用Ctrl+C
结束一个python
程序,有两种方法。
处理KeyboardInterrupt异常
当用户键盘输入Ctrl+C
时,python
程序会抛出KeyboardInterrupt
异常。只需要捕获这个异常时结束程序即可。
import syscount=0try: while True: count+=1 print(count)except KeyboardInterrupt as e: print('end') sys.exit(0)# 结束进程
处理SIGINT信号
用户按下Ctrl+C
,linux
内核会向进程发送SIGINT
信号,只需在信号处理函数内退出即可。
import signalimport sysdef signal_handler(signal, frame): #print('end')# 注意,不能在信号处理函数内使用不可重入函数 x = 3 sys.exit(0)signal.signal(signal.SIGINT, signal_handler)count=0while True: count+=1 print(count)
multiprocessing多进程编程
下面是一个用multiprocessing
写的多进程处理程序。
import multiprocessingimport timedef func(msg): while True: print('process-{}'.format(msg)) time.sleep(1)if __name__ == "__main__": P = multiprocessing.Pool(processes=4)# 4 threads for i in range(10): P.apply_async(func, (i,)) P.close() P.join()
为了让该程序能处理Ctrl+C
,尝试了上面两种方法。加KeyboardInterrupt
异常处理,SIGINT
信号处理,发现都不行。这是为什么呢? Ctrl+C
本质上就是让内核发送SIGINT
信号,那我们先了解一下linux
信号的机制。
linux信号机制
信号是进程间通信的一种机制。OS内核也可以因为内部事件,给进程发送信号(检查进程表中进程的状态,有选择的发送),通知进程发生了某个事件。
multiprocessing源码解释
在上例使用multiprocessing
的代码中,我们首先创建进程池P
,然后异步执行进程
。
这两步都做了些什么呢,我们可以到multiprocessing
源码中看看。multiprocessing
是python
自带的库,所以其源码一般位于python
安装路径的lib
下,如C:\Python27\Lib\multiprocessing
。通过源码可以发现:
创建进程池P
: 创建了Pool对象。异步执行进程
: 执行Pool对象的成员函数apply_async
,返回结果为ApplyResult
类型的对象。
在ApplyResult
类的构造函数__init__
中,第一行代码是threading.Condition(threading.Lock())
。Condition
对象初始化时,就是被lock住的,SIGINT
信号就没法被lock住后面的代码捕获,所以Ctrl+C
对multiprocessing
无效。
结论
multiprocessing
创建的每个进程,在进程执行函数结束(返回)之前,都是被lock住的。被lock住的代码没法接收到SIGINT
信号。
关于怎么解决这个问题,[3]中有一些workaround。最好的解决办法,应该就是其中提到的用python3
的concurrent.futures
包来做多进程,而不是用multiprocessing
。
参考
- [1] python 多线程编程并不能真正利用多核的CPU, http://www.cnblogs.com/cloudaice/archive/2012/01/26/python_thread03.html
- [2] Linux 信号signal处理机制, http://www.cnblogs.com/taobataoma/archive/2007/08/30/875743.html
- [3] Solution. https://segmentfault.com/a/1190000004172444
- 从multiprocessing源码理解其对SIGINT信号的屏蔽
- 关于信号函数处理过程中对信号的屏蔽理解。
- SIGINT信号
- 屏蔽程序对信号响应的代码
- SIGINT信号导致的usleep无效问题
- SIGINT信号导致的usleep无效问题
- 对信号卷积的理解
- Linux的信号 SIGALRM和SIGINT的使用示例
- sleep会被其它信号(SIGALRM,SIGINT)唤醒的测试
- SIGINT,SIGQUIT,SIGTERM等终止进程信号的区别
- 信号屏蔽的小点
- 对信号频谱的理解 (转)
- Linux信号列表(sigint,sigtstp..)
- Linux信号列表(sigint,sigtstp..)
- linux信号 - SIGINT和SIGALRM
- Linux信号列表(sigint,sigtstp..)
- Linux信号列表(sigint,sigtstp..)
- 对图像高频信号和低频信号的理解
- spring
- PTA 排座位(25 分)
- 「算法精解_C语言描述」 链表_双向链表的实现与分析
- JZOJ 5459. 【NOIP2017提高A组冲刺11.7】密室
- 后缀自动机 笔记
- 从multiprocessing源码理解其对SIGINT信号的屏蔽
- NOIP模拟 图【最小生成树】
- 文章标题
- 洛谷 NOIP 模拟 DAY2
- 会动的圆
- navigator对象
- NYOJ 过河问题
- 入阵曲+将军令
- 2输入一个字符判断是否属于a-zA-Z之间如果是请是属于a-z还是A-Z并且输出值。