Python MPI
全局解释器锁(GIL,Global Interpreter Lock)¶
Python代码的执行由Python虚拟机(解释器)来控制。
对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同时只有一个线程在运行。所以就会出现尽管你设置了多线程的任务,但是只能跑一个的情况。
但是I/O密集的程序(爬虫)相对好一点,因为I/O操作会调用内建的操作系统C代码,所以这时会释放GIL锁,达到部分多线程的效果。
通常我们用的解释器是官方实现的CPython,要真正利用多核,除非重写一个不带GIL的解释器。
Python 鸡肋的多线程¶
Python 多进程正常实现¶
通过多进程实现多核任务。多个Python进程有各自独立的GIL锁,互不影响。
子进程调用实例¶
def TIMEOUT_COMMAND(command, timeout=10):
"""call shell-command and either return its output or kill it
if it doesn't normally exit within timeout seconds and return None"""
import subprocess, datetime, os, time, signal
cmd = command.split(" ")
start = datetime.datetime.now()
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,encoding="utf-8",preexec_fn=os.setsid) #让 Popen 成立自己的进程组
# https://www.cnblogs.com/gracefulb/p/6893166.html
# 因此利用这个特性,就可以通过 preexec_fn 参数让 Popen 成立自己的进程组, 然后再向进程组发送 SIGTERM 或 SIGKILL,中止 subprocess.Popen 所启动进程的子子孙孙。当然,前提是这些子子孙孙中没有进程再调用 setsid 分裂自立门户。
ic("BHive-noUseOSACA-before",process.pid,process.poll())
while process.poll() != 208: # poll()(好像BHive208是正常结束)返回0 正常结束, 1 sleep, 2 子进程不存在,-15 kill,None 在运行
ic("BHive-noUseOSACA-During",process.pid,process.poll())
time.sleep(0.2)
now = datetime.datetime.now()
if (now - start).seconds> timeout:
# BHive有子进程,需要杀死进程组。但是需要新生成进程组,不然会把自己kill掉
os.killpg(os.getpgid(process.pid), signal.SIGKILL)
# os.killpg(process.pid, signal.SIGTERM) SIGTERM不一定会kill,可能会被忽略,要看代码实现
# https://blog.csdn.net/zhupenghui176/article/details/109097737
# os.waitpid(-1, os.WNOHANG)
(killPid,killSig) = os.waitpid(process.pid, 0)
if killPid != process.pid or killSig!=9:
errorPrint("TIMEOUT_COMMAND kill failed! killPid %d process.pid %d killSig %d" % (killPid, process.pid, killSig))
ic("Killed",process.pid,process.poll())
return None
ic("BHive-noUseOSACA-Finished",process.pid,process.poll())
return process.stdout.readlines()
使用Queue或者Pipe通讯¶
https://github.com/Kirrito-k423/BHive-Prediction-Compare/blob/main/pythonTest/0326_newBar_qcjiang.py
多核的解决方法:调用C语言的链接库¶
把一些计算密集型任务用C语言编写,然后把.so链接库内容加载到Python中,因为执行C代码,GIL锁会释放,这样一来,就可以做到每个核都跑一个线程的目的!
进程池¶
子进程实例¶
### check process create time
### kill all process by name
### 以为的原因
subProcess.pool 返回程序状态的时候,除了运行和结束状态,还有休眠等其他状态。也就是程序在发射之后并不是直接进入运行状态的。判断程序是否超时不能通过判断是否运行,因为一开始while循环进不去
而应该是判断是否正常结束(208是BHive结束返回值,不同程序不同)
### 继续分析
实际debug还是有
![](https://pic.shaojiemike.top/img/20220625173740.png)
在debug输出里没有这些pid
check了,输出的个数是符合的。
不懂了,我都没调用,这僵尸进程哪里来的?除非是BHive产生的。
### 实际原因
调用的Bhive会产生子进程,原本的python实现不能杀死子进程的子进程。需要改用杀死进程组的实现
### 杀死进程组
![](https://pic.shaojiemike.top/img/20220625185611.png)
可能设定是timeout是20秒,但是htop程序运行了2分钟也没有kill。这是正常的,因为主程序挤占资源导致挂起了,导致无法及时判断和kill
需要进一步的研究学习¶
暂无
遇到的问题¶
暂无
开题缘由、总结、反思、吐槽~~¶
参考文献¶
无