跳转至

Python MPI

全局解释器锁(GIL,Global Interpreter Lock)

Python代码的执行由Python虚拟机(解释器)来控制。

对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同时只有一个线程在运行。所以就会出现尽管你设置了多线程的任务,但是只能跑一个的情况。

但是I/O密集的程序(爬虫)相对好一点,因为I/O操作会调用内建的操作系统C代码,所以这时会释放GIL锁,达到部分多线程的效果。

通常我们用的解释器是官方实现的CPython,要真正利用多核,除非重写一个不带GIL的解释器。

Python 鸡肋的多线程

from threading import Thread

Python 多进程正常实现

通过多进程实现多核任务。多个Python进程有各自独立的GIL锁,互不影响。

from multiprocessing import Process

子进程调用实例

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锁会释放,这样一来,就可以做到每个核都跑一个线程的目的!

进程池

from mpi4py import MPI

子进程实例

python的子程序实现有问题,运行中,会有bhive-reg遗留下来(多达20个,需要按照下面手动kill,这也是核数建议为总核数的1/3的原因
### check process create time
ps -eo pid,lstart,cmd |grep bhive
date
### kill all process by name
 sudo ps -ef | grep 'bhive-re' | grep -v grep | awk '{print $2}' | sudo xargs -r kill -9
### 以为的原因 subProcess.pool 返回程序状态的时候,除了运行和结束状态,还有休眠等其他状态。也就是程序在发射之后并不是直接进入运行状态的。判断程序是否超时不能通过判断是否运行,因为一开始while循环进不去
while process.poll() is None:
而应该是判断是否正常结束(208是BHive结束返回值,不同程序不同)
while process.poll() != 208:
### 继续分析 实际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

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献