Swoole具备进程管理模块,用来代替PHP的pcntl拓展。
Process进程是系统中十分昂贵的资源,创建进程消耗很大,可以使用vmstat指令查看系统每秒进程切换次数
1.PHP自带pcntl拓展存在很多不足
- pcntl没有提供进程间通信的功能
- pcntl不支持重定向标准输入和输出
- pcntl只提供了fork这样原始的接口,容易使用错误
- swoole_process提供了比pcntl更强大的功能,更易用的API,使PHP在多进程编程方面更加轻松。
2.swoole_process提供了如下特性
- swoole_process提供了基于unixsock的进程间通信,使用很简单只需调用write/read或者push/pop即可
- swoole_process支持重定向标准输入和输出,在子进程内echo不会打印屏幕,而是写入管道,读键盘 输入可以重定向为*管道读取数据
- 配合swoole_event模块,创建的PHP子进程可以异步的事件驱动模式
swoole_process提供了exec接口,创建的进程可以执行其他程序,与原PHP父进程之间可以方便的通信
3.创建进程:new swoole_process()
函数原型:swoole_process::__construct(callable $function, $redirect_stdin_stdout = false, $create_pipe = true);
参数:
- callable $function:子进程创建成功后要执行的函数,底层会自动将函数保存在对象的callback属性上,若要更改执行函数则可赋值新的函数在对象的callback属性。
- $redirect_stdin_stdout:重定向子进程的标准输入输出,启动此选项后,子进程输出内容不是打印到屏幕而是写入主进程管道,读取键盘输入变成从管道中读取数据,默认为阻塞读取。
- $create_pipe:是否创建管道,启动重定向后此项强制为1/true,如果子进程内没有进程间通信科设置为false。
- 管道类型:0/false => 不创建管道,1/true => 管道类型将设置为SOCK_STREAM(流式),2 => 管道类型将设置为SOCK_DGRAM(数据包)
4.启动进程:swoole_process->start
执行fork系统调用,启动进程
函数原型:int swoole_process->start();
返回参数:创建成功返回子进程的PID,创建失败返回false
启动后可用属性:
- $process->pid属性为子进程的PID
- $process->pipe属性为管道的文件描述符
5.向管道写入数据:swoole_process->write
函数原型:int swoole_process->write(string $data);
参数:$data的长度在Linux系统下最大不超过8K,MacOS/FreeBSD下最大不超过2K
父/子进程调用write,子/父进程可调用read接收数据
同步模式:进程内未使用任何异步IO,则管道为同步阻塞模式,如果缓冲区满了,将阻塞直到write操作完成。如Task进程就是同步阻塞模式。
异步模式:进程内使用了异步IO,如swoole_event_add(进程事件),进程内wirte操作变成异步模式,swoole底层会监听可写事件,自动完成管道写入。
6.从管道中读取数据:swoole_process->read
函数原型:function swoole_process->read(int $buffer_size=8192) : string | bool;
- $buffer_size是缓冲区的大小,默认为8192,最大不超过64K
- 管道类型为DGRAM数据报(2)时,read可以读取完整的一个数据包
- 管道类型为STREAM(1/true)时,read是流式的,需要自行处理包完整性问题
- 读取成功返回二进制数据字符串,读取失败返回false
7.添加进程事件:异步IO,swoole_event_add
swoole_event_add函数用于将一个socket加入到底层的reactor事件监听中。此函数可以用在Server或Client模式下。
函数原型:bool swoole_event_add(int $sock, mixed $read_callback, mixed $write_callback = null, int $flags = null);
- int $sock:可以为一下三种类型
1.int,就是文件描述符,包括swoole_client的socket,以及第三方扩展的socket(比如mysql)
2.stream资源,就是stream_socket_client/fsockopen创建的资源
3.sockets资源,就是sockets扩展中socket_create创建的资源,需要在编译时加入 ./configure –enable-sockets - mixed $read_callback:可读回调函数
- mixed $write_callback:可写事件回调,可以是字符串函数名、对象+方法、类静态方法或匿名函数,当此socket可读时回调指定的函数。
- int $flags:事件类型的掩码,可选择关闭/开启可读可写事件,如SWOOLE_EVENT_READ,SWOOLE_EVENT_WRITE,或者SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE
8.创建同步进程
1 | <?php |
将脚本上传至服务器并启动,可以看到,无重定向打印了$worker的内容和PID,重定向输出了Hello
9.创建异步进程
因为子进程会继承父进程的内存和IO句柄,所以如果父进程要创建多个子进程,务必要等待创建完毕后再使用swoole_event_add/异步swoole_client/定时器/信号等异步IO函数。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28<?php
//进程池 存储进程
$workers = [];
//进程数量
$worker_num = 3;
//创建并启动进程
for($i=0;$i<$worker_num;$i++){
$process = new swoole_process('doProcess'); //创建单独新进程
$pid = $process->start(); //启动进程并获取进程ID
$workers[$pid] = $process; //将进程存入进程池
}
//编写进程执行函数
function doProcess(swoole_process $process){
$process->write("PID : (".$process->pid.")\t CallbackFunction(".$process->callback .")".PHP_EOL);
echo "Write Msg : PID(".$process->pid.")\t CallbackFunction(".$process->callback .")".PHP_EOL;
}
//添加进程事件 向每个子进程添加需要执行的事件
foreach ($workers as $process) {
//子进程也会包含此事件
swoole_event_add($process->pipe,function($pipe) use($process){
$data = $process->read();
echo "Receive Msg : ".$data.PHP_EOL;
});
}
将脚本上传至服务器并启动,可以看到成功将PID和Callback函数写入管道并且读出来了