PHP PCNTL多进程编程
admin
2023-07-04 09:44:16
0次

PHP中的PCNTL可以实现多进程编程,由于项目场景需要,试用了一下,感触颇多,也长了不少见识,就此对遇到的问题小做一个总结,以备不时之需。


问题一:fork泛滥

我想在一个父进程中起10个子程来完成我的工作,代码如下:

for($i = 0; $i < 10; $i++) {
    $pid = pcntl_fork();
    if($pid  == -1) {
        echo "Could not fork!\n";
        exit(1);
    }
    if(!$pid) {
        //child process workspace
        //TODO
        Api::refreshCache();        
    }
}

由于Api::refreshCache逻辑中有数据库操作,代码一执行,就把DB搞死了,报了N多个too many connections。我以为是DB原本就抽风了,检查DB,正常。

最终发现,这一段代码fork的可不是10个子进程,而是

20 + 21 + 22+ 23 + 24 + ... + 29 = 210-1 = 1023 个子进程。

恐怖了吧?这是因为子进程又fork子进程,并且子进程不共享父进程$i变量更新的值,由此导致数量成指数关系增长。

为了避免这个问题,代码修改如下:

for($i = 0; $i < 10; $i++) {
    $pid = pcntl_fork();
    if($pid  == -1) {
        echo "Could not fork!\n";
        exit(1);
    }
    if(!$pid) {
        //child process workspace
        //TODO
        Api::refreshCache(); 
        exit; //子进程逻辑执行完后,马上退出,以免往下走再fork子进程,不好控制     
    }
}

只要在子进程逻辑执行完后,加一个exit,一切都在撑握中了。这样,只有一个父进程,父进程后续对子进程的管理也会清晰很多。


问题二:单例模式下DB连接被虐

/*
 * 前面或远或近的地方,已经有一个$db = &MySql::getInstance();了
 */
for($i = 0; $i < 10; $i++) {
    $pid = pcntl_fork();
    if($pid  == -1) {
        echo "Could not fork!\n";
        exit(1);
    }
    if(!$pid) {
        //child process workspace
        //TODO
        $db = &MySql::getInstance();
        $sql = "XXX";
        $result = $db->getAll($sql);
        exit;
    }
}

这段代码,十有八九都会报mysql has gone away.或者其它一些数据fetch方面的错误。究其原因,是因为各个子进程创建时,就已经继承了父进程一份完全一样的拷贝。对象可以拷贝,但是已创建的连接可不能拷贝成多个,由此产生的结果,就是各个进程都使用同一个mysql连接,各干各的事,最终产生莫名其妙的冲突。

解决办法:

我们显然不可能完全保证在fork进程之前,父进程不会创建mysql连接实例,因此,解决方案只能靠子进程本身了。可以想象,我们只需要在子进程中获取的实例只与当前进程相关,这个问题就不存在了。解决办法就是稍微改造一下mysql类实例化的静态方式,与当前进程ID绑定。

public static function &getInstance() {
    static $instances = array();
    $key = getmypid(); //获取当前进程ID
    if(empty($instances[$key])) {
        //实例化mysql类动作
        $classname = __CLASS__;
        $instances[$key] = new $classname();
    }
    return $instances[$key];
}


总结:子进程创建时,拷贝了父进程当时拥有的所有资源,虽说后面对资源的修改互不影响,但DB连接却还是同一个,造成运行混乱。

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...