愤怒的小菜

小菜的成长博客

通过多进程使PHP异步执行代码

应用场景:比如在浏览一些页面时,可以让浏览器提前得到响应,然后通过创建子进程来执行异步代码(比如:统计数累加、来源统计等)

DEMO:

public function Test1Action(){

 

    echo "string";

 

    $this->asyncode(function(){

        sleep(3);

        $mongo    =    Mongo_Db::getInstance();

        $colle    =    $mongo->collection('TEST');

        $colle->insert(array('time'=>time(),'value'=>'异步进程'));

    });

 

    return false;

}


异步方法:

/**

 * 异步执行代码

 *     需要安装pcntl扩展,若没有安装则是同步执行。

 *     注意:此方法要在最后调用,否则程序意外的exit后可能会产生僵尸进程!

 * @param $fun    函数对象

 * @param $istest true:改为同步调试 false:异步执行(默认)

 * @example

 *     $this->asyncode(function(){

 *          sleep(2);

 *          file_put_contents('xiaocai.txt', time());

 *     });

 */

private function asyncode($fun,$istest=false){

    //验证扩展

    if(!function_exists('pcntl_fork') || !function_exists('posix_kill')){

        $fun();

        return false;

    }

    //调试模式

    if($istest){

        $fun();

        return true;

    }

    //创建进程

    $pid = pcntl_fork();

    if($pid == -1){

        throw new Exception(' couldn\'t fork.');

    }else{

        if($pid){

            //父进程执行

            $status = 0;

            pcntl_wait($status); //阻塞子进程等待响应(防止僵尸进程)

            if($status!=0){/*子进程异常退出*/}

            exit;

        }else{

            //子进程执行

            $gpid = pcntl_fork();

            if( $gpid < 0){

                throw new Exception(' couldn\'t fork.');

            }elseif($gpid > 0){

                //孙进程执行

                $status = 0;

                $status = pcntl_wait($status,1); //孙进程非阻塞异步执行

                if($status!=0){/*孙进程异常退出*/}

                posix_kill(getmypid(), SIGTERM); //kill掉子进程

                exit(0);

            }else{

                //孙进程执行

                @$fun();

                posix_kill(getmypid(), SIGTERM); //kill掉孙进程

                exit(0);

            }

        }

    }

}


方法中通过两次pcntl_fork()来避免产生僵尸进程,可以使用以下方法处理僵尸进程.


查找僵尸进程

ps -el | grep php

杀死僵尸进程

ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]' | awk '{print $2}' | xargs kill -9

(kill -9 父进程id)


 
评论

© 愤怒的小菜 | Powered by LOFTER