PHP实现多进程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHP实现多进程相关的知识,希望对你有一定的参考价值。

swoole 实现php多进程同步

PHP 本身是一个强领域的语言,主要应用于web开发。
PHP 也可以进行多进程开发,但是使用的第三方扩展。
下面我们演示使用 swoole 实现 PHP多进程,且自定义进程名称,可启动及停止。
自定义进程名前缀:tprocess-
主进程名为:tprocess-master
子进程名为:tprocess-xxx              xxx 为数字

停止进程有多种方式,比如 kill -9 强制杀死,但这样会导致任务在中间中断,出现脏数据
我们使用信号的方式,通知子进程,在下一个任务时退出。

在使用多进程时,容易出现僵尸进程,为了避免僵尸进程,我们使用 信号接收子进程退消息,并回收资源。

运行

nohup php -f tproc.php start &

停止,会发送信号给运行的主进程,由主进程通知子进程结束

php -f tproc.php stop

启动后效果如下:

[[email protected] test]$ ps -ef | grep tprocess
jingwu   10126  4844  0 00:16 pts/5    00:00:00 tprocess-master
jingwu   10127 10126  0 00:16 pts/5    00:00:00 tprocess-0
jingwu   10128 10126  0 00:16 pts/5    00:00:00 tprocess-1
jingwu   10129 10126  0 00:16 pts/5    00:00:00 tprocess-2
jingwu   10130 10126  0 00:16 pts/5    00:00:00 tprocess-3
jingwu   10131 10126  0 00:16 pts/5    00:00:00 tprocess-4

tproc.php

error_reporting(E_ALL);
ini_set(‘display_errors‘, ‘1‘);
ini_set(‘error_log‘, ‘/tmp/tprocess_error.log‘);

define(‘PROC_LIMIT‘, 5);

class ProcConfig {
    static $status = null;
}   

//查找对应的进程,我们直接查找系统 /proc 目录下的文件
//这样做是因为,在生产环境不一定会开放 exec 等函数,有一定的局限
//查找系统文件还可以避免维护进程ID文件
function proc_find() {
    $baseDir = ‘/proc‘;
    $rows = scandir(‘/proc‘);
    $procTitles = [];
    foreach($rows as $pid) {
        if(!is_numeric($pid)) continue;
        $cmdlineFile = sprintf("%s/%s/cmdline", $baseDir, $pid);
        if(!file_exists($cmdlineFile)) continue;
        $title = trim(file_get_contents($cmdlineFile));
        if(substr($title, 0, 9) != ‘tprocess-‘) continue;
        $procTitles[$title] = $pid;
    }
    return $procTitles;
}   

//检查子进程,因异常或任务结束而导致子进程结束
//通过检查,维持一定数量的子进程
function proc_check() {
    $titles = [‘ip‘ => [], ‘domain‘ => []];
    for($i = 0; $i < PROC_LIMIT; $i++) $titles[‘ip‘][] = [‘tprocess-‘.$i, $i];

    $procs = proc_find();
    foreach($titles as $key => $items) {
        foreach($items as $row) {
            $title = $row[0];
            $index = $row[1];
            if(isset($procs[$title])) continue;
            $worker = new swoole_process(function (swoole_process $process) use($index) {proc_child($process, $index);}, true);
            $procid = $worker->start();
        }
    }
}

//守护进程,负责启动及监控子进程
function proc_master() {
    $procs = proc_find();
    if(isset($procs[‘tprocess-master‘])) {
        print("Dispatch[running]守护进程已经启动\n");
        exit(0);
    }
    //主进程异常结束,子进程未结束,结束所有子进程
    if(!isset($procs[‘tprocess-master‘]) && $procs) {
        foreach($procs as $title => $pid) posix_kill($pid, 9);
    }

    //设置主进程名
    swoole_set_process_name(‘tprocess-master‘);
}    

//worker进程,负责处理数据
function proc_child(swoole_process $process, $index) {
    $title = ‘tprocess-‘.$index;
    $process->name($title);
    while(1) {
        if(ProcConfig::$status->get()) exit(1);
        sleep(5);
    }
}

$action = isset($argv[1]) ? $argv[1] : ‘‘;
if($action == "start") {
    //进程状态位,用于标识是否可以退出
    ProcConfig::$status = new swoole_atomic(0);

    proc_master();
    print("started worker\n");
    sleep(2);
    proc_check();

    //注册子进程退出监听函数,避免僵尸进程
    swoole_process::signal(SIGCHLD, function($sig) {
        while ($ret =  swoole_process::wait(false)) {
            file_put_contents(‘/tmp/tprocess_defunct.log‘, "child process killed: {$sig}-{$ret[‘pid‘]}\n", FILE_APPEND);
            proc_check();
        }
    });

    //主进程监听 SIGUSR2 信号,并设置进程状态位,通知子进程结束
    swoole_process::signal(SIGUSR2, function($sig) {
        ProcConfig::$status->add(1);
        print("receive SIGUSR2 to stop worker\n");
        exit(0);
    });

}else if($action == "stop") {
    $procs = proc_find();
    if(isset($procs[‘tprocess-master‘])) {
        posix_kill($procs[‘tprocess-master‘], SIGUSR2);
    }
    print("stop disptch worker is ok\n");
    exit(0);
} else {
    echo <<< EOF
 cmd [action]

 action list:
     start
     stop

 eg:
     php -f ./tproc.php start
     php -f ./tproc.php stop

EOF;
} 

以上是关于PHP实现多进程的主要内容,如果未能解决你的问题,请参考以下文章

Linux下实现PHP多进程的方法分享

多线程编程

PHP实现多进程

php如何实现多继承?

php实现多进程多线程

PHP多进程实现