Swoole Process
什么是swoole_process呢?
swoole_process
是基于C语言封装的进程管理模块,方便PHP多进程编程。swoole_process
内置管道、消息队列接口,可以方便地实现进程间通信。swoole_process
提供了自定义信号管理
swoole_process
是swoole提供的进程管理模块,用来替代PHP的pcntl
扩展。
PHP自带的pcntl
扩展有什么缺陷呢?
pcntl
没有提供进程间通信的功能pcntl
不支持重定向标准输入和输出pcntl
只提供了fork
这样原始的接口,容易使用错误。swoole_process
提供了比pcntl
更强大的功能,更易用的API,使PHP在多进程编程方面更加轻松。
使用vmstat
指令查看操作系统美妙进程切换的次数。
$ vmstat 1 1000
swoole_process有什么特性呢?
进程在系统中是非常昂贵的资源,创建进程开销很大,另外创建的进程过多会导致进程切换开销大幅上升。
swoole_process
提供了基于UNIX SOCK进程间通信,使用简单只需要调用write
、read
、push
、pop
即可。swoole_process
支持重定向标准输入和输出,在子进程中echo
不会打印到屏幕而会写入到管道,读取键盘输入也可以重定向为管道读取数据。- 配置
swoole_event
模块,创建PHP子进程可以异步的事件驱动模式。 swoole_process
提供了exec
接口,创建进程可以执行其他程序,与原PHP父进程之间可以方便地通信。
例如:创建管道类型的子进程,定时向子进程的管道中写入数据并读取。
$ vim process.php
<?php
class Process
{private $process;/**构造函数 */public function __construct($redirect_stdin_stdout = false, $pipe_type = 1, $deamon = false){//创建子进程$this->process = new swoole_process([$this, "run"], $redirect_stdin_stdout, $pipe_type);//是否设置为后台守护进程if($deamon){$nochdir = true;//是否切换当前目录到根目录$noclose = false;//是否关闭标准输入输出的文件描述符$this->process->daemon($nochdir, $noclose);}//启动子进程,成功返回子进程的PID。$pid = $this->process->start();if(!$pid){$errno = swoole_errno();//获取最近一次系统调用的错误码$errtype = 1;//错误类型 1表示标准的UNIX Error$errmsg = swoole_strerror($errno, $errtype);//将错误码转换为错误信息echo "errno {$errno} errmsg {$errmsg}".PHP_EOL;}else{echo "pid {$pid}".PHP_EOL;}//{"pipe":null,"callback":null,"msgQueueId":null,"msgQueueKey":null,"pid":5657,"id":null}//echo json_encode($this->process);//是否使用管道if($pipe_type > 0){//获取子进程的管道$pipe = $this->process->pipe;//echo $pipe.PHP_EOL;//异步非阻塞读取:将管道添加到底层reactor事件监听中swoole_event_add($pipe, function($pipe){//子进程从管道中读取数据$recv = $this->process->read();echo "[read] {$recv}".PHP_EOL;});}}/** 运行子进程*/public function run($worker){//设置间隔时钟定时器$msec = 1000;swoole_timer_tick($msec, function($timer_id){static $index = 0;$index = $index + 1;//子进程写入消息$message = "hello";$result = $this->process->write($message);if($result === false){$errno = swoole_last_error();//获取最近一次Swoole底层的错误码$errmsg = swoole_strerror($errno, 9);//将错误码转化为错误信息echo "[error] errno {$errno} errmsg:{$errmsg}".PHP_EOL;}else{echo "[write] success {$result} bytes".PHP_EOL;}//写入10次if($index == 3){//删除定时器swoole_timer_clear($timer_id);}});}
}$process = new Process();
//设置异步信号监听
swoole_process::signal(SIGCHLD, function($signo){//收回结束运行的子进程,非阻塞模式while($ret = swoole_process::wait(false)){echo "[wait] ".json_encode($ret).PHP_EOL;echo "pid = ".$ret["pid"].PHP_EOL;}
});
运行
$ php process.php
pid 6478
[write] success 5 bytes
[read] hello
[write] success 5 bytes
[read] hello
[write] success 5 bytes
[read] hello
[wait] {"pid":6478,"code":0,"signal":0}
pid = 6478
构造函数construct
创建子进程
原型
swoole_process:__construct(callable $function,$redirect_stdin_stdout = false,$create_pipe = true
)
参数
- 参数1:
callable $function
子进程创建成功后要执行的回调函数 - 参数2:
$redirect_stdin_stdout
重定向子进程的标准输入和输出 - 参数3:
$pipe_type
管道类型 - 参数4:
$enable_coroutine
是否启用协程
返回
$this->process = new swoole_process([$this, "run"], $redirect_stdin_stdout, $pipe_type
);
echo json_encode($this->process);
打印输出
{"pipe":null,//管道的文件描述符"callback":null,"msgQueueId":null,"msgQueueKey":null,"pid":5657,//当前进程的PID"id":nul//当前进程的ID
l}
由此可以获得子进程的管道文件描述符
$pipe = $this->process->pipe;
守护进程 daemon
使当前进程蜕变为一个守护进程,蜕变为守护进程时当前进程的PID将会发生变化,可使用getmypid()
获取当前进程的PID。
原型
低于Swoole1.9.1版本
bool Process::daemon(bool $nochdir = false, bool $noclose = false
);
高于或等于Swoole1.9.1版本,修改了参数默认值。
bool Process::daemon(bool $nochdir = true, bool $noclose = true
);
参数
- 参数1:
bool $nochdir
是否切换当前目录为根目录 - 参数2:
bool $noclose
是否关闭标准输入输出文件描述符
启动进程 start
执行fork
系统调用启动进程
原型
function Process->start():int
若子进程启动(创建)成功则返回其PID,若创建失败则返回false
。可使用swoole_errno
和swoole_strerror
获得错误码和错误信息。
//启动子进程,成功返回子进程的PID。
$pid = $this->process->start();
if(!$pid){$errno = swoole_errno();//获取最近一次系统调用的错误码$errtype = 1;//错误类型 1表示标准的UNIX Error$errmsg = swoole_strerror($errno, $errtype);//将错误码转换为错误信息echo "errno {$errno} errmsg {$errmsg}".PHP_EOL;
}else{echo "pid {$pid}".PHP_EOL;
}
- 子进程会继承父进程的内存和文件句柄
- 子进程在启动时会清除父进程继承的
EventLoop
、Signal
、Timer
。 - 执行后子进程会保持父进程的内存和资源,如果父进程内创建了一个Redis连接,那么在子进程中会保留此对象,所有操作都是对同一个连接进行的。
读取数据read
从管道中读取数据,若管道类型$pipe_type = 1
为SOCK_STREAM
流式时,读取的是流式的,此时需要自行处理包完整性问题。若管道类型$pipe_type = 2
为SOCK_DGRAM
数据报时,可以读取完整的一个数据包。若读取成功则会返回二进制数据字符串,若读取失败则会返回false
。
原型
- 同步阻塞读取
function Process->read(int $buffer_size = 8192): string | bool
- 异步非阻塞读取
若采用异步模式读取,则需使用swoole_event_add
将管道加入到事件循环中,即可变为异步模式。由于Swoole底层采用epoll
的LT
模式,因此swoole_event_add
添加到事件监听后,在事件发生后回调函数中必须调用read
方法读取socket
中的数据,否则底层会持续触发事件回调。
//获取子进程的管道
$pipe = $this->process->pipe;
//echo $pipe.PHP_EOL;
//异步非阻塞读取:将管道添加到底层reactor事件监听中
swoole_event_add($pipe, function($pipe){//子进程从管道中读取数据$data = $this->process->read();echo "[recv] {$data}".PHP_EOL;
});
参数
int $buffer_size
表示缓冲区的大小,默认为8192字节即8KB,最大不要超过64KB。
写入数据write
向管道内写入数据,Swoole底层使用UNIX Sock实现通信,UNIX Sock是内核实现的全内存通信,无任何IO消耗。管道通信默认是流式的SOCK_STREAM
,写入的数据在读取时可能会被底层合并,可以设置swoole_process
构造函数的第三个参数$pipe_type
管道类型为2即SOCK_DGRAM
使其改变为数据报式。
原型
function Process->write(string $data) int | bool;
参数
string $data
表示要发送的数据
返回
- 写入成功:返回写入数据的字节数
- 写入失败:返回
false
可使用swoole_last_error()
获取错误码。
例如
//子进程写入消息
$message = "hello";
$result = $this->process->write($message);
if($result === false){$errno = swoole_last_error();//获取最近一次Swoole底层的错误码$errmsg = swoole_strerror($errno, 9);//将错误码转化为错误信息echo "[error] errno {$errno} errmsg:{$errmsg}".PHP_EOL;
}else{echo "[write] success {$result} bytes".PHP_EOL;
}
回收进程wait
回收结束运行的子进程,子进程结束必须要执行wait
进行回收,否则子进程会变成僵尸进程。
使用Process
作为监控父进程,创建管理子进程时,父类必须注册信号SIGCHLD
对退出的进程执行wait
,否则子进程一旦被kill
将会引起父进程退出。
//设置异步信号监听
swoole_process::signal(SIGCHLD, function($signo){//收回结束运行的子进程,非阻塞模式while($ret = swoole_process::wait(false)){echo json_encode($ret).PHP_EOL;echo "pid = ".$ret["pid"].PHP_EOL;}
});
原型
array Process::wait(bool $blocking = true);
参数
$blocking
仅仅在Swoole1.7.10+版本中可用。bool $blocking = true
表示可以指定是否阻塞等待,默认为阻塞。
返回
- 操作成功:返回一个数组包含子进程的PID、退出状态码、哪种信号
KILL
{"pid":6478,"code":0,"signal":0
}
- 操作失败:返回
false
未完待续...
Swoole Process相关推荐
- swoole process进程 多分发
<?php /** * Created by PhpStorm. * User: whitneywang * Date: 2018/6/4 * Time: 14:14 */ //第二个参数为tr ...
- php swoole process,Swoole_process实现进程池的方法
Swoole的进程之间有两种通信方式,一种是消息队列(queue),另一种是管道(pipe),对swoole_process 的研究在swoole中显得尤为重要. IO多路复用 swoole 中的io ...
- php swoole process,PHP swoole的process模块创建和使用子进程操作示例
本文实例讲述了PHP swoole的process模块创建和使用子进程操作.分享给大家供大家参考,具体如下: swoole中为我们提供了一个进程管理模块 Process,替换PHP的 pcntl 扩展 ...
- 利用Swoole同时更新多台服务器代码
一个小型网站的架构, 前面一台负载均衡, 后面几台web服务器. 更新代码成了难题, 一个一个FTP传不现实, 而且容易漏传,导致两个WEB服务器的代码都不一致. 一个简单的想法: 利用Websock ...
- 【Swoole系列3.5】进程池与进程管理器
进程池与进程管理器 我们已经学习过单个进程相关的内容,也学习了进程间如何进行通信,但是,一个一个地进程还是非常不好管理,这不,Swoole 就为我们直接准备好了进程池以及进程管理相关的工具. 进程池 ...
- PHP如何解决swoole守护进程Redis假死 ,mysql断线重连问题?
PHP如何解决swoole守护进程Redis假死 ,mysql断线重连问题? 最近公司有个项目,要举办一个线上活动,我这边负责提供接口记录用户访问记录,与操作记录,由于活动参与人数可能比较多,为了不影 ...
- php swoft 应用,Swoole 在 Swoft 中的应用
date: 2017-12-14 21:34:51 title: swoole 在 swoft 中的应用 上一篇 blog - swoft 源码解读 反响还不错, 不少同学推荐再加一篇, 讲解一下 s ...
- php 开启常驻进程,swoole如何常驻进程
后端经常会有类似这样的场景,某个脚本,需要不断的重复运行,这个时候,最好有一个守护程序,帮助我们不断地自动地拉起这些脚本进程,让它自动地重复运行. swoole 的进程管理模块就提供了进程间通信的功能 ...
- Swoole server浅析
ps:在看的过程中如果有遇到任何问题可以留言或者到我的学习交流群一起交流学习. ★我的php学习交流社区--[点击加].群内管理已准备好 整理好的BAT等一线大厂进阶知识体系备好(相关学习资料以及笔面 ...
最新文章
- 转载知乎上的一篇:“ 面向对象编程的弊端是什么?”
- oracle某个表丢失,丢失一个控制文件并恢复数据库
- 为什么程序员都不喜欢使用 switch ,而是大量的 if……else if ?
- 面试:Spring Boot 中的条件注解底层是如何实现的?
- 用JAVA制作微型操作系统4月23日情况
- 方立勋_30天掌握JavaWeb_自定义标签
- java 计算协方差_Java的深度:通过协方差暴露的API泄漏
- 论文浅尝 | 使用孪生BERT网络生成句子的嵌入表示
- eclipse中导入SVN项目步骤
- 你以为你懂MySQL索引?阿里的面试官:你还太嫩!
- QuickHit游戏
- 客户端如何获取服务器控件的值(原理与实例)
- 用python写二维码_Python用5行代码写一个自定义简单二维码
- 软考:McCabe环路复杂度计算方法
- mysql查询所有男生中姓王的_数据库6.22
- linux如何伪装ip,如何伪装你的IP(二)
- mac端锐捷无法验证服务器,还在为mac无法用锐捷认证校园网登陆而郁闷吗?
- 并行计算(三):并行计算效能的评估
- python实际应用2-拆分PDF
- 百度bae专业版svn提交问题