Swoole基础进阶之进程篇-笔记

Swoole基础进阶之进程篇-笔记

首页角色扮演Project T更新时间:2024-07-15
01开张课、照镜子、设置自定义进程名称

获取当前进程ID

https://www.php.net/manual/zh/function.posix-getpid.php

<?php $id = posix_getpid(); echo $id; while (1){ sleep(10); } //查看进程 ps -ef | grep xxx

设置进程名称

https://www.php.net/manual/zh/function.cli-set-process-title

<?php $id = posix_getpid(); cli_set_process_title('001'); echo $id; while (1){ sleep(10); }02创建第一个子进程、获取子进程ID、回收子进程

root 7986 7985 0 11:18 pts/1 00:00:00 [php] <defunct>

<?php $id = posix_getpid(); cli_set_process_title('php1'); echo $id.PHP_EOL; $child = new \Swoole\Process(function(){ echo '我是一个子进程'.posix_getpid().PHP_EOL; }); $child->start(); while (1){ sleep(10); }

使用主进程创建子进程,每个子进程结束后子进程没有被主进程收回资源,子进程会变成僵尸进程。

每个子进程结束后,父进程必须都要执行一次 wait() 进行回收,否则子进程会变成僵尸进程,会浪费操作系统的进程资源。

<?php //主进程代码 $id = posix_getpid(); cli_set_process_title('php-main'); echo $id.PHP_EOL; $child = new \Swoole\Process(function(){ //子进程执行 cli_set_process_title('php-child'); echo '我是一个子进程'.posix_getpid().PHP_EOL; while (1){ //死循环,不让进程不退出 sleep(10); } }); $child->start(); \Swoole\Process::wait(); //回收子进程资源 //主进程代码 while (1){ sleep(10); }03重定向子进程标准输出 、父进程获取子进程数据初步

父子进程相互通信并且交互数据

Swoole\Process::__construct(callable $function, bool $redirect_stdin_stdout = false, int $pipe_type = SOCK_DGRAM, bool $enable_coroutine = false);

bool $redirect_stdin_stdout

<?php $id = posix_getpid(); cli_set_process_title('php-main'); echo $id.PHP_EOL; $child = new \Swoole\Process(function(){ //子进程执行 cli_set_process_title('php-child'); echo 'my name is:'; while (1){ sleep(10); } },true); // true 重定向写入到主进程管道 $child->start(); //从管道中读取数据 https://wiki.swoole.com/wiki/page/217.html echo $child->read().'jackin.chen'; \Swoole\Process::wait(); //主进程代码 while (1){ sleep(10); }

array Process::wait(bool $blocking = true); $result = array('code' => 0, 'pid' => 15001, 'signal' => 15);

子进程结束必须要执行wait进行回收,否则子进程会变成僵尸进程

<?php $id = posix_getpid(); cli_set_process_title('php-main'); echo $id.PHP_EOL; $child = new \Swoole\Process(function(){ //子进程执行 cli_set_process_title('php-child'); $num = 0; while (1){ echo 'my name is:'. $num; sleep(2); } },true); // true 重定向写入到主进程管道 $child->start(); \Swoole\Process::wait(false); // 非阻塞 //主进程代码 while (1){ echo $child->read().'jackin.chen'.PHP_EOL; sleep(2); }04多个子进程的回收、Linux信号入门

<?php cli_set_process_title('php-main'); echo '当前进程ID:'.posix_getpid().PHP_EOL; use \Swoole\Process; $child1 = new Process(function() { //子进程执行 cli_set_process_title('php-child1'); echo 'child1:'.posix_getpid().PHP_EOL; while (1) { sleep(2); } }); $child1->start(); $child2 = new Process(function() { cli_set_process_title('php-child2'); echo 'child2:'.posix_getpid().PHP_EOL; }); $child2->start(); Process::wait(); //回收子进程

<?php cli_set_process_title('php-main'); echo '当前进程ID:'.posix_getpid().PHP_EOL; use \Swoole\Process; $child1 = new Process(function() { //子进程执行 cli_set_process_title('php-child1'); echo 'child1:'.posix_getpid().PHP_EOL; while (1) { sleep(2); } }); $child1->start(); $child2 = new Process(function() { cli_set_process_title('php-child2'); echo 'child2:'.posix_getpid().PHP_EOL; }); $child2->start(); //第一种方案 /* for($i=0;$i<2;$i ){ Process::wait(); //等待回收子进程 }*/ //第二种方案 :在异步信号回调中执行wait Process::signal(SIGCHLD, function($sig) { //必须为false,非阻塞模式 while($ret = Process::wait(false)) { var_dump($ret); } }); //信号发生时可能同时有多个子进程退出 //必须循环执行wait直到返回false

[root@localhost ~]# ps -ef | grep php

root 16569 6315 0 14:15 pts/1 00:00:00 php-main

root 16570 16569 0 14:15 pts/1 00:00:00 php-child1

Linux信号完整对照表

信号

取值

默认动作

含义(发出信号的原因)

SIGHUP

1

Term

终端的挂断或进程死亡

SIGINT

2

Term

来自键盘上的中断信号

SIGQUIT

3

Core

来自键盘上的离开信号

SIGILL

4

Core

非法指令

SIGABRT

6

Core

来自abort的异常信号

SIGFPE

8

Core

浮点例外

SIGKILL

9

Term

*死

SIGSEGV

11

Core

段非法错误(内存引用无效)

SIGPIPE

13

Term

管道损坏:向一个没有读进程的管道写数据

SIGALRM

14

Term

来自alarm的计时器导师

05在子进程中运行httpserver、修改进程名称

Server只能用于php-cli环境,在其他环境下会抛出致命错误

构建Http\Server对象

$serv = new Swoole\Server('0.0.0.0', 9501, SWOOLE_BASE, SWOOLE_SOCK_TCP);

创建一个异步服务器程序,支持TCP、UDP、UnixSocket 3种协议,支持IPv4和IPv6,支持SSL/TLS单向双向证书的隧道加密。使用者无需关注底层实现细节,仅需要设置网络事件的回调函数即可。

请勿在使用Server创建之前调用其他异步IO的API,否则将会创建失败。可以在Server启动后onWorkerStart回调函数中使用。

设置运行时参数

$serv->set(array( 'worker_num' => 4, 'daemonize' => true, 'backlog' => 128, ));注册事件回调函数

$serv->on('Connect', 'my_onConnect'); $serv->on('Receive', 'my_onReceive'); $serv->on('Close', 'my_onClose');

PHP中可以使用4种回调函数的风格

启动服务器

$serv->start();属性列表

$serv->manager_pid; //管理进程的PID,通过向管理进程发送SIGUSR1信号可实现柔性重启 $serv->master_pid; //主进程的PID,通过向主进程发送SIGTERM信号可安全关闭服务器 $serv->connections; //当前服务器的客户端连接,可使用foreach遍历所有连接运行流程图进程/线程结构图onStart

启动后在主进程(master)的主线程回调此函数,函数原型

function onStart(Server $server);

在此事件之前Server已进行了如下操作

接下来要执行

onStart回调中,仅允许echo、打印Log、修改进程名称。不得执行其他操作。onWorkerStart和onStart回调是在不同进程中并行执行的,不存在先后顺序。

可以在onStart回调中,将$serv->master_pid和$serv->manager_pid的值保存到一个文件中。这样可以编写脚本,向这两个PID发送信号来实现关闭和重启的操作。

onStart事件在Master进程的主线程中被调用。

在onStart中创建的全局资源对象不能在Worker进程中被使用,因为发生onStart调用时,worker进程已经创建好了 新创建的对象在主进程内,Worker进程无法访问到此内存区域 因此全局对象创建的代码需要放置在Server::start之前

<?php use \Swoole\Process; echo '当前进程ID:'.posix_getpid().PHP_EOL; cli_set_process_title('swoole-main'); $child = new Process(function() { $http = new Swoole\Http\Server("0.0.0.0", 9501); $http->set([ "worker_num"=>4 ]); $http->on('request', function ($request, $response) { $response->end("<h1>Hello Swoole. #".rand(1000, 9999)."</h1>"); }); $http->on('start', function ( $serv) { cli_set_process_title('swoole-master'); }); $http->on('managerstart', function ($serv) { cli_set_process_title('swoole-manager'); }); $http->on('workerstart', function ($serv, $worker_id) { cli_set_process_title('swoole-worker'); }); $http->start(); }); $child->start(); echo '当前进程名称:'.cli_get_process_title().PHP_EOL; Process::signal(SIGCHLD, function($sig) { //必须为false,非阻塞模式 while($ret = Process::wait(false)) { var_dump($ret); } });事件

Swoole\Server是事件驱动模式,所有的业务逻辑代码必须写在事件回调函数中。当特定的网络事件发生后,底层会主动回调指定的PHP函数。

事件执行顺序

onStart/onManagerStart/onWorkerStart 3个事件的执行顺序是不确定的

异常捕获

$serv->on('Receive', function() { try { //some code } catch(Exception $e) { //exception code } }协程模式

Swoole2/4版本支持了协程,使用协程后事件回调函数将会并发地执行。协程是一种用户态线程实现,没有额外的调度消耗,仅占用内存。使用协程模式,可以理解为“每次事件回调函数都会创建一个新的线程去执行,事件回调函数执行完成后,线程退出”。

如果希望关闭协程,可设置:

$server->set(["enable_coroutine" => false, ]);06场景练习监控文件变动、进程感知

1、比如有个指定配置文件db.conf在当前 项目目录下的tmp文件夹中 2、文件一旦发生变动则进程能感知到,然后发送什么消息等等 3、这种功能是很适合用多进程监控来做的

<?php use \Swoole\Process; echo '当前进程ID:'.posix_getpid().PHP_EOL; cli_set_process_title('swoole-main'); $child = new Process(function() { $file = __DIR__.'/db.conf'; $md5 = md5_file($file); while (true){ $md5_check = md5_file($file); if(strcmp($md5,$md5_check)){ echo '文件被修改'.date('Y-m-d H:i:s').PHP_EOL; } sleep(1); } }); $child->start(); echo '当前进程名称:'.cli_get_process_title().PHP_EOL; Process::wait(); /* Process::signal(SIGCHLD, function($sig) { //必须为false,非阻塞模式 while($ret = Process::wait(false)) { var_dump($ret); } }); ?07场景练习mysql简易巡检监控

!mysql监控 1、连接是否正常I 2、查询连接数 3、查询线程使用情况则进程能刚知到,然后发送什么消息等等

这种功能是很适合用多进程监控来做的 注意:今天的代码需要把swoole升级到4.3.X Peel install swoole 即可

监控:

select count(*) as c from information_schema.processlist select * from information_schema.GLOBAL_STATUS where VARIABLE_NAME like 'Thread%' select * from information_schema.GLOBAL_STATUS where VARIABLE_NAME like 'Abort%' select * from information_schema.processlist

进程里面运行协程代码

<?php use \Swoole\Process; use \Swoole\Coroutine\MySQL; echo '当前进程ID:'.posix_getpid().PHP_EOL; cli_set_process_title('swoole-main'); $child = new Process(function() { $swoole_mysql = new MySQL(); $swoole_mysql->connect([ 'host' => '192.168.33.10', 'port' => 3306, 'user' => 'root', 'password' => 'root', 'database' => 'information_schema', ]); $checkConnect = "select 1"; $checkProcessCount = "select count(*) as c from information_schema.processlist"; $checkThread = "select * from information_schema.GLOBAL_STATUS where VARIABLE_NAME like 'Thread%'"; //$res = $swoole_mysql->query('select 1'); //测试 while (true){ $checkResult[] = date('Y-m-d H:i:s'); try{ $swoole_mysql->query($checkConnect); $checkResult[] = '检查连接正常'; $res = $swoole_mysql->query($checkProcessCount); $checkResult[] = '当前连接数'.$res[0]['c']; $res = $swoole_mysql->query($checkThread); $checkResult[] = '检查线程情况'; foreach ($res as $row){ foreach ($row as $key => $value){ $checkResult[] = $key.':'.$value; } } $checkResult[] = '---------------------'; echo implode(PHP_EOL,$checkResult); }catch (Exception $exception){ echo $exception->getMessage().PHP_EOL; } sleep(5); } },false,0,true); $child->start(); echo '当前进程名称:'.cli_get_process_title().PHP_EOL; Process::wait(); /* Process::signal(SIGCHLD, function($sig) { //必须为false,非阻塞模式 while($ret = Process::wait(false)) { var_dump($ret); } }); */08场景练习 多进程监控订单表状态、父子进程通信

Process->write

向管道内写入数据。

function Process->write(string $data) int | bool;

测试数据

<?php use \Swoole\Process; use \Swoole\Coroutine\MySQL; echo '当前进程ID:'.posix_getpid().PHP_EOL; cli_set_process_title('swoole-main'); /** CREATE TABLE `zerg`.`swoole_order` ( `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '表ID', `order_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '订单号', `is_pay` tinyint(2) NOT NULL DEFAULT 0 COMMENT '是否支付', `is_notice` tinyint(2) NOT NULL DEFAULT 0 COMMENT '是否通知', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact; */ $child = new Process(function() { $swoole_mysql = new MySQL(); $swoole_mysql->connect([ 'host' => '192.168.33.10', 'port' => 3306, 'user' => 'root', 'password' => 'root', 'database' => 'zerg', ]); while (true){ try{ $test = 'insert into swoole_order (order_no) value ("'.md5(time()).'")'; $swoole_mysql->query($test); var_dump($swoole_mysql); }catch (Exception $exception){ echo $exception->getMessage().PHP_EOL; } sleep(1); } },false,0,true); $child->start(); echo '当前进程名称:'.cli_get_process_title().PHP_EOL; Process::wait(); /* Process::signal(SIGCHLD, function($sig) { //必须为false,非阻塞模式 while($ret = Process::wait(false)) { var_dump($ret); } }); */

案例代码:父子进程通信,子进程之间通信

<?php use \Swoole\Process; use \Swoole\Coroutine\MySQL; echo '当前进程ID:'.posix_getpid().PHP_EOL; cli_set_process_title('swoole-main'); //该子进程负责查询已支付并未通知订单信息 $child_select = new Process(function(Process $process) { $swoole_mysql = new MySQL(); $swoole_mysql->connect([ 'host' => '192.168.33.10', 'port' => 3306, 'user' => 'root', 'password' => 'root', 'database' => 'zerg', ]); while (true){ try{ $order = "select id,order_no,is_pay,is_notice from swoole_order where is_pay=1 and is_notice=0 limit 1"; $res = $swoole_mysql->query($order); if($res && count($res)){ $process->write($res[0]['order_no']); } }catch (Exception $exception){ echo $exception->getMessage().PHP_EOL; } sleep(3); } },false,1,true); //1:创建SOCK_STREAM类型管道 $child_select->start(); //该子进程负责对已支持订单发送通知 $child_notice = new Process(function(Process $process) { while (true){ $order_notice = $process->read(); if($order_notice){ echo '进程2获取到订单号:'.$order_notice.PHP_EOL; } usleep(0.5 *1000 * 1000); //微秒 } },false,1,true); //1:创建SOCK_STREAM类型管道 $child_notice->start(); //主进程接收子进程的消息后往另一个子进程写消息 while (true){ $order_no = $child_select->read(); if($order_no){ $child_notice->write($order_no); } usleep(0.5 *1000 * 1000); //微秒 } echo '当前进程名称:'.cli_get_process_title().PHP_EOL; Process::signal(SIGCHLD, function($sig) { //必须为false,非阻塞模式 while($ret = Process::wait(false)) { var_dump($ret); } });09场景练习 多进程监控订单表状态、队列通信

使用队列通信

<?php use \Swoole\Process; use \Swoole\Coroutine\MySQL; echo '当前进程ID:'.posix_getpid().PHP_EOL; cli_set_process_title('swoole-main'); //该子进程负责查询已支付并未通知订单信息 $child_select = new Process(function(Process $process) { $swoole_mysql = new MySQL(); $swoole_mysql->connect([ 'host' => '192.168.33.10', 'port' => 3306, 'user' => 'root', 'password' => 'root', 'database' => 'zerg', ]); $offset = 0; while (true){ try{ $order = "select order_no from swoole_order where is_pay=1 and is_notice=0 limit {$offset},1"; $res = $swoole_mysql->query($order); if($res && count($res)){ $process->push($res[0]['order_no']); } }catch (Exception $exception){ echo $exception->getMessage().PHP_EOL; } $offset ; sleep(3); } },false,1,true); //1:创建SOCK_STREAM类型管道 $child_select->useQueue(2); $child_select->start(); //该子进程负责对已支持订单发送通知 $child_notice1 = new Process(function(Process $process) { while (true){ $order_notice = $process->pop(); if($order_notice){ echo '1子进程从消息队列取消息:'.$order_notice.PHP_EOL; } usleep(0.5 *1000 * 1000); //微秒 } },false,1,true); //1:创建SOCK_STREAM类型管道 $child_notice1->useQueue(2); $child_notice1->start(); //该子进程负责对已支持订单发送通知 $child_notice2 = new Process(function(Process $process) { while (true){ $order_notice = $process->pop(); if($order_notice){ echo '2子进程从消息队列取消息:'.$order_notice.PHP_EOL; } usleep(0.5 *1000 * 1000); //微秒 } },false,1,true); //1:创建SOCK_STREAM类型管道 $child_notice2->useQueue(2); $child_notice2->start(); /** * 思路: * 1、进程之间消息不会发生同时争夺 * 2、如果发送通知比较耗时,没有处理完又从数据库中读取消息 -> 考虑使用redis锁实现 */ echo '当前进程名称:'.cli_get_process_title().PHP_EOL; Process::wait(); /* Process::signal(SIGCHLD, function($sig) { //必须为false,非阻塞模式 while($ret = Process::wait(false)) { var_dump($ret); } }); */10调用外部程序成为子进程之调用Go写的程序、设置进程名称

执行一个外部程序,此函数是exec系统调用的封装。

bool Process->exec(string $execfile, array $args)

执行成功后,当前进程的代码段将会被新程序替换。子进程蜕变成另外一套程序。父进程与当前进程仍然是父子进程关系。

父进程与新进程之间可以通过标准输入输出进行通信,必须启用标准输入输出重定向。

$execfile必须使用绝对路径,否则会报文件不存在错误 由于exec系统调用会使用指定的程序覆盖当前程序,子进程需要读写标准输出与父进程进行通信 如果未指定redirect_stdin_stdout = true,执行exec后子进程与父进程无法通信

$process = new \Swoole\Process(function (\Swoole\Process $childProcess) { // 不支持这种写法 // $childProcess->exec('/usr/local/bin/php /var/www/project/yii-best-practice/cli/yii t/index -m=123 abc xyz'); // 封装 exec 系统调用 // 绝对路径 // 参数必须分开放到数组中 $childProcess->exec('/usr/local/bin/php', ['/var/www/project/yii-best-practice/cli/yii', 't/index', '-m=123', 'abc', 'xyz']); // exec 系统调用 }); $process->start(); // 启动子进程

父进程与exec子进程使用管道进行通信:

// exec - 与exec进程进行管道通信 use Swoole\Process; $process = new Process(function (Process $worker) { $worker->exec('/bin/echo', ['hello']); $worker->write('hello'); }, true); // 需要启用标准输入输出重定向 $process->start(); echo "from exec: ". $process->read(). "\n";

<?php # 案例 use \Swoole\Process; echo '当前进程ID:'.posix_getpid().PHP_EOL; cli_set_process_title('swoole-main'); $process = new Process(function (Process $p){ echo '123'; //该代码段将会被新程序替换,不会执行 $p->exec('/usr/bin/php',[__DIR__.'/run.php','name']); echo 'abc'; //该代码段将会被新程序替换,不会执行 },true,0,true); // 父子进程进行管道通信,需要启用标准输入输出重定向 $process->start(); while (true){ $str = $process->read(); echo $str; } Process::signal(SIGCHLD, function($sig) { //必须为false,非阻塞模式 while($ret = Process::wait(false)) { // var_dump($ret); } });

<?php # run.php cli_set_process_title('swoole-exec'); while (true){ echo date('Y-m-d H:i:s').PHP_EOL; sleep(3); }

[root@localhost ~]# ps -ef | grep swoole root 3494 3064 0 01:00 pts/0 00:00:00 swoole-main root 3495 3494 0 01:00 pts/0 00:00:00 swoole-exec

11(附加课)调用外部程序成为子进程之调用Go写的程序、设置进程名称

$process = new Process(function (Process $p){ echo '123'; //该代码段将会被新程序替换,不会执行 $p->exec('/usr/run.go',[]); echo 'abc'; //该代码段将会被新程序替换,不会执行 },true,0,true); // 父子进程进行管道通信,需要启用标准输入输出重定向 $process->start();12易进程管理器(1)读取配置、启动多个子进程

#pm.conf [child] send = /usr/bin/env php send.php move = /usr/bin/env php move.php

<?php //function.php use \Swoole\Process; function init(){ $config = parse_ini_file('pm.conf',true); $child = $config['child']; foreach ($child as $name => $item){ $params = explode(' ',$item); $process = new Process(function (Process $p) use($params){ $p->exec($params[0],array_splice($params,1)); }); $process->start(); } } //查看linux下的信号列表 kill -l

<?php //move.php cli_set_process_title('swoole-move'); while (true){ echo 'move-data'.PHP_EOL; sleep(3); }

<?php //pm.php 进程入口 use \Swoole\Process; echo '当前进程ID:'.posix_getpid().PHP_EOL; cli_set_process_title('swoole-main'); //包含公共函数 require 'function.php'; //初始化进程 init(); //在异步信号回调中执行wait Process::signal(SIGCHLD, function($sig) { //必须为false,非阻塞模式 while($ret = Process::wait(false)) { //执行回收后的处理逻辑,比如拉起一个新的进程 var_dump($ret); } }); //回收结束运行的子进程。 Process::wait(true);

<?php //send.php cli_set_process_title('swoole-send'); while (true){ echo 'send-data'.PHP_EOL; sleep(3); }13简易进程管理器(2)监控配置文件、支持动态添加子进程

<?php //pm.php use \Swoole\Process; echo '当前进程ID:'.posix_getpid().PHP_EOL; cli_set_process_title('swoole-main'); //包含公共函数 require 'function.php'; //核心进程 intCore(); //启动进程 init(); //主进程拦截子进程发送信号 Process::signal(SIGUSR1, function() { echo '进程正在重新配置'.date('Y-m-d H:i:s').PHP_EOL; init(); }); //在异步信号回调中执行wait //查看linux下的信号列表 kill -l Process::signal(SIGCHLD, function() { //必须为false,非阻塞模式 while($ret = Process::wait(false)) { //执行回收后的处理逻辑,比如拉起一个新的进程 var_dump($ret); } }); //回收结束运行的子进程。 //Process::wait(true);

<?php //function.php use \Swoole\Process; //创建进程 $processList = []; //主进程变量,管理进程变量 function init(){ global $processList; // $config = parse_ini_file('pm.conf',true); $child = $config['child']; foreach ($child as $name => $item){ $params = explode(' ',$item); $process = new Process(function (Process $p) use($params){ $p->exec($params[0],array_splice($params,1)); }); $pid = $process->start();//用户自定义进程 $processList[$name] = [ 'pid' =>$pid, 'date' =>date('Y-m-d H:i:s'), ]; ; } } //运行 核心子进程 function intCore(){ $process = new Process(function (Process $p) { cli_set_process_title('swoole-watch'); watchConfig(); //运行子进程,子父进程通信发送信号 }); $process->start(); } //监听文件 function watchConfig(){ $child = new Process(function() { $file = __DIR__.'/pm.conf'; $md5 = md5_file($file); while (true){ $md5_check = md5_file($file); if(strcmp($md5,$md5_check)){ //子进程和父进程通信,发送信号 Process::kill(posix_getppid(),SIGUSR1); //向父进程发送账户 echo posix_getppid().'文件被修改'.date('Y-m-d H:i:s').PHP_EOL; } sleep(3); } }); $child->start(); }14简易进程管理器(2)监控配置文件、支持动态删除子进程

<?php //function.php use \Swoole\Process; //创建进程 $processList = []; //主进程变量,管理进程变量 function init(){ global $processList; // $config = parse_ini_file('pm.conf',true); $child = $config['child']; foreach ($child as $name => $item){ $params = explode(' ',$item); $process = new Process(function (Process $p) use($params){ $p->exec($params[0],array_splice($params,1)); }); $pid = $process->start();//用户自定义进程 $processList[$name] = [ 'pid' =>$pid, 'date' =>date('Y-m-d H:i:s'), ]; ; } //删除进程 rmProcess($child); } //运行 核心子进程 function intCore(){ $process = new Process(function (Process $p) { cli_set_process_title('swoole-watch'); watchConfig(); //运行子进程,子父进程通信发送信号 }); $process->start(); } //监听文件 function watchConfig(){ $child = new Process(function() { $file = __DIR__.'/pm.conf'; $md5 = md5_file($file); while (true){ $md5_check = md5_file($file); if(strcmp($md5,$md5_check)){ //子进程和父进程通信,发送信号 Process::kill(posix_getppid(),SIGUSR1); //向父进程发送信号 echo posix_getppid().'文件被修改'.date('Y-m-d H:i:s').PHP_EOL; } sleep(3); } }); $child->start(); } function rmProcess($child){ global $processList; $process = array_diff_key($processList,$child); foreach ($process as $pkey => $pvalue){ Process::kill($pkey['pid'],SIGTERM); unset($processList[$pkey]); } }15简易进程管理器支持API查看子进程运行情况

<?php //使用文件共享进程状态 $http = new Swoole\Http\Server('0.0.0.0', 9501); $http->set([ 'worker_num' => 1 ]); $http->on('Request', function ($request, $response) { $response->header('Content-Type', 'text/html; charset=utf-8'); $content = file_get_contents('pm.status'); $response->end($content); }); $http->start();

function httpWeb(){ $process = new Process(function (Process $p){ $p->exec('/usr/bin/env',['php',__DIR__.'/http.php']); }); $pid = $process->start();//用户自定义进程 }16简易进程管理器 子进程退出时修改状态、API状态同步17简易定时任务(1)crontab表达式解析、定时执行函数20补充课时swoole 4.4.x之后子进程回收代码的问题处理

Process主进程自动退出 https://github.com/swoole/swoole-src/issues/2731

从4.4版本开始底层将不再将信号监听作为 EventLoop Exit 的 block 条件。有两个解决方案:

  1. 添加一个 tick 定时器
  2. 改为阻塞等待进程退出

use Swoole\Process; cli_set_process_title("master"); $manager=new Process(function(Process $process){ cli_set_process_title("manager"); while(true) { echo "a".PHP_EOL; sleep(1); } }); $ret = Process::wait(); echo "PID={$ret['pid']}\n";



查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved