跳到主要内容

swoole进程基础继续

调用外部程序成为子进程

swoole Process exec函数文档地址:https://wiki.swoole.com/#/process/process?id=exec

<?php

require 'vendor/autoload.php';
use Swoole\Process;
use Swoole\Coroutine\MySQL;

echo "当前进程ID: ".posix_getpid().PHP_EOL;
cli_set_process_title("my_main"); // 设置了进程名称

$child1 = new Process(function (Process $p) {
// 设置子进程名称
cli_set_process_title("my_child1");
}, false, 0, true);

$child1->start();

Process::signal(SIGCHLD, function ($sig) {
// 必须为 false 非阻塞模式
while ($ret = Process::wait(false)) {
echo "PID={$ret['pid']}\n";
}
});

先写一个简单的代码

echo "wujie".PHP_EOL;
root@8199b542ec1e:/var/www# php child.php
wujie

文档上说:string $execfile,是指定可执行文件的绝对路径,但是我们这里直接使用php child.php很明显不是,我们需要先找到php可执行文件的绝对路径

root@8199b542ec1e:/var/www# which php
/usr/local/bin/php
# 这样执行
$(which php) child.php

或者

/usr/bin/env php child.php
警告

如果php不在环境变量里,就不能使用env的方式

<?php

require 'vendor/autoload.php';

use Swoole\Process;
use Swoole\Coroutine\MySQL;

echo "当前进程ID: " . posix_getpid() . PHP_EOL;
cli_set_process_title("my_main"); // 设置了进程名称

$child1 = new Process(function (Process $p) {
// 设置子进程名称
cli_set_process_title("my_child1");
$p->exec("/usr/bin/env", ['php', './child.php']);
echo "abc";
}, true, 0, true);

$child1->start();

while (1) {
$ret = $child1->read();
echo $ret;
usleep(0.5 * 1000 * 1000);
}

Process::signal(SIGCHLD, function ($sig) {
// 必须为 false 非阻塞模式
while ($ret = Process::wait(false)) {
echo "PID={$ret['pid']}\n";
}
});


child.php

<?php

cli_set_process_title("my_child1");
while (1) {
echo "wujie".PHP_EOL;
sleep(5);
}

多进程示例

<?php
use Swoole\Process;

$funcMap = array('methodOne', 'methodTwo', 'methodThree');
$worker_num = 3;//创建的进程数

for ($i = 0; $i < $worker_num; $i++) {
$process = new Process($funcMap[$i]);
$pid = $process->start();
sleep(2);
}

while (1) {
$ret = Process::wait();
if ($ret) {// $ret 是个数组 code是进程退出状态码,
$pid = $ret['pid'];
echo PHP_EOL . "Worker Exit, PID=" . $pid . PHP_EOL;
} else {
break;
}
}

function methodOne(Process $worker)
{// 第一个处理
echo $worker->pid . PHP_EOL;
}

function methodTwo(Process $worker)
{// 第二个处理
echo $worker->pid . PHP_EOL;
}

function methodThree(Process $worker)
{// 第三个处理
echo $worker->pid . PHP_EOL;
}

简易进程管理器

读取配置、启动多个子进程

使用parse_ini_file解析配置文件获取配置参数

p.conf
[childs]
child1=/usr/bin/env php /data/work/php/process/swoolepro/child1.php
child2=/usr/bin/env php /data/work/php/process/swoolepro/child2.php
<?php

$config = parse_ini_file("./pm/p.conf", true);
var_dump($config);
➜  swoolepro php test.php                                      
array(1) {
["childs"]=>
array(2) {
["child1"]=>
string(60) "/usr/bin/env php /data/work/php/process/swoolepro/child1.php"
["child2"]=>
string(60) "/usr/bin/env php /data/work/php/process/swoolepro/child2.php"
}
}

函数集中编写

functions.php
<?php

function init()
{
$config = parse_ini_file("./pm/p.conf", true);
$childs = $config['childs'];
foreach ($childs as $key => $value) {
// key 作为进程名称
// value 根据空格切为数组
$exec_params = explode(' ', $value);
$p = new Swoole\Process(function (\Swoole\Process $process) use ($exec_params) {
// 0: 可执行文件路径
// 后面 需要执行的内容
$process->exec($exec_params[0], array_slice($exec_params, 1));
});
$p->start();
}
}

准备2个子进程执行的程序

<?php

cli_set_process_title("mychild 1");
while (1) {
echo "child1".PHP_EOL;
sleep(5);
}
 <?php

cli_set_process_title("mychild 2");
while (1) {
echo "child2".PHP_EOL;
sleep(5);
}

主进程代码

pm.php
<?php

//require "../vendor/autoload.php";
require_once "./pm/functions.php";

use Swoole\Process;

echo "当前进程ID: " . posix_getpid() . PHP_EOL;
cli_set_process_title("my_main");

init();

while (1) {
$ret = Process::wait();
if ($ret) {
$pid = $ret['pid'];
echo PHP_EOL . "Worker Exit, PID=" . $pid . PHP_EOL;
} else {
break;
}
}


配合一段C代码

demo1.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>

pid_t pid = 0;

void sigchld_handler(int sig) {
printf("father call the SIGCHLD signal handler. num=%d\n", sig);
}

int main()
{
signal(SIGCHLD,sigchld_handler);
pid = fork();

if(pid == -1){
exit(1);
} else if(pid == 0){ // child code
printf("child process is running, pid = %d.\n",getpid());
} else { // father code
pause();
printf("father process runs again.\n");
}

return 0;
}
gcc demo1.c

./demo1.out

child process is running, pid = xxxx
father call the SIGCHLD signal handler. num=11
father process runs again.