swoole深入学习 4. process
swoole-1.7.2增加了一个进程管理模块,用来替代PHP的pcntl扩展。pcntl是php新增的一个多进程扩展,用来实现多进程,但是有很多不完善的地方,swoole 就完善了这些地方,而且使得使用非常简单。
创建一个多进程
swoole创建多进程很简单:new Swoole\Process('callback_function')
就可以了。
比如我要同时创建10个进程,就for 循环10次就可以了。
for($i=0; $i<=10 ; $i++){
$process = new Swoole\Process('callback_function');
$pid = $process->start();
echo PHP_EOL . $pid;//
}
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
非常简单。
来个具体的例子,我们对比下普通的模式和多进程模式的时间速度区别:
多进程下并发3次,每次循环1亿次。和普通模式下。
<?php
echo time() .PHP_EOL ;
$worker_num = 3;//创建的进程数
for ($i=0; $i < $worker_num ; $i++) {
$process = new Swoole\Process('callback_function');
$pid = $process->start();
}
function callback_function($worker) {
for($i=0;$i<100000000;$i++){}
echo time() .PHP_EOL;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
看下打印的时间, 算最大的时间,总共用了8秒。
➜ swoole git:(master) ✗ php test.php
1481791259 #开始时间,没有被阻塞。
➜ swoole git:(master) ✗
1481791267 #
1481791267
1481791267
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
具体的资源占用:
$ time php test.php
0.04s user
0.02s system
50% cpu
0.129 total
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
再看下普通循环模式:
<?php
echo time() .PHP_EOL;
for($i=0;$i<100000000;$i++){}
for($i=0;$i<100000000;$i++){}
for($i=0;$i<100000000;$i++){}
echo time() .PHP_EOL;
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
看下打印时间,用了16秒。
1481791591
1481791607
- 1
- 2
- 1
- 2
具体的资源占用:
time php test.php
15.09s user
0.11s system
96% cpu
15.720 total
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
进程间的通信
如果是非常简单的多进程执行任务,那么进程间就不需要通讯了,实际情况下,很多业务是需要通讯的,比如,发邮件,如果自进程发送失败了,那么是要通知主进程的等等。
再看进程间通信之前,先看下 Swoole\Process 的几个参数:
Swoole\Process(mixed $function, $redirect_stdin_stdout = false, $create_pipe = true);
它有三个参数:
$function:子进程创建成功后要执行的函数
$redirect_stdin_stdout:重定向子进程的标准输入和输出。 设置为true,则在进程内echo将不是打印屏幕,而是写入到管道,读取键盘输入将变为从管道中读取数据。 默认为false,阻塞读取。
$create_pipe:是否创建管道,启用$redirect_stdin_stdout后,此选项将忽略用户参数,强制为true 如果子进程内没有进程间通信,可以设置为false。
swoole_process进程间支持3种通信方式:
- 1、管道pipe
- 2、消息队列
- 3、信号
管道通信
管道通信是swoole_process默认的一种通信方式。当然我们也可以在实例化的时候通过参数来设定:
$process = new Swoole\Process('callback_function', false, true);
这样就创建了一个管道通信进程。我们打印下$process
这个对象的值:
var_dump($process)
object(swoole_process)#1 (3) {
["pipe"]=>
int(2)
["callback"]=>
string(26) "callback_function"
["pid"]=>
int(4333)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
里面有个字段pipe
是管道id,还有一个pid
是进程id,所以:
每次创建一个进程后,就会随之创建一个管道,主进程想和哪一个进程通信,就向那个进程的管道写入/读取数据。
管道有2个方法,分别来写入数据,和读取数据。
write() 和 read()
来个例子,看下如何通过管道通信
<?php
/**
* process 管道通信
* User: yangyi
* Date: 2016/12/9
* Time: 17:10
*/
//进程数量
$worker_num = 2;
$workers = [];
for ($i = 0; $i < $worker_num; $i++) {
$process = new Swoole\Process('callback_function', false);
$pid = $process->start();
//将每一个进程的句柄存起来
$workers[$pid] = $process;
}
// 主进程,通过管道给子进程发送数据
foreach ($workers as $pid => $process) {
//向子进程管道里写内容:$process->write($data);
$process->write("hello worker[$pid]\n");
//从子进程管道里面读取信息:$process->read();
echo "From Worker: ".$process->read();
}
//子进程执行的回调函数
function callback_function($worker){
//从主进程管道中读取
$recv = $worker->read();
echo PHP_EOL. "From Master: $recv\n";
//向主进程管道中写入数据
$worker->write("hello master , this pipe is ". $worker->pipe ."; this pid is ".$worker->pid."\n");
$worker->exit(0);
}
- 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
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 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
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
运行看下效果:
$ php process_pipe.php
From Master: hello worker[6759]
From Worker: hello master , this pipe is 4; this pid is 6759
From Master: hello worker[6760]
From Worker: hello master , this pipe is 6; this pid is 6760
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
注意 主进程和子进程中的 read()
不能一开始都读,得写反。不然管道中没数据,就会阻塞住了。
所以可以参考下面的图:
所以一般的顺序是:
master-->write()
work-->read()
work-->write()
master-->read()
这样才能有序的使用通道,才不会被阻塞。而且是一对一的,write 2 次,也要read 2次,先write先read。
第二个参数 $redirect_stdin_stdout
说,设置为 true ,子进程会将 echo 写入到主管道。我把上面的代码改一下,看下输出结果是啥。
$process = new Swoole\Process('callback_function', true, true);
紧紧改动了这一行,再看下:
//进程数量
$worker_num = 2;
$workers = [];
for ($i = 0; $i < $worker_num; $i++) {
$process = new Swoole\Process('callback_function', true);
$pid = $process->start();
//将每一个进程的句柄存起来
$workers[$pid] = $process;
}
// 主进程,通过管道给子进程发送数据
foreach ($workers as $pid => $process) {
//向子进程管道里写内容:$process->write($data);
$process->write("hello worker[$pid]\n");
//从子进程管道里面读取信息:$process->read();
echo "From Worker: ".$process->read();
}
//子进程执行的回调函数
function callback_function($worker){
//从主进程管道中读取
$recv = $worker->read();
//这个echo 相当于在往master管道里写数据。write('From Master: hello worker[9251]')
echo "From Master: $recv\n";
//第二次写, 但是主进程没有第二次read(),所以没有被读到。
$worker->write("hello master , this pipe is ". $worker->pipe ."; this pid is ".$worker->pid."\n");
$worker->exit(0);
}
- 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
- 29
- 30
- 31
- 32
- 33
- 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
- 29
- 30
- 31
- 32
- 33
运行下输出结果为:
$ php test.php
From Worker: From Master: hello worker[9251]
From Worker: From Master: hello worker[9252]
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
来分析下,因为$redirect_stdin_stdout
为true,所以子进程中echo的内容就到了主管道里面,而不是打印在屏幕上,所以,主进程从管道里读到的内容,就是子进程中echo的内容。
也就造成了上面的输出结果。
那么如何使子进程中的第二个write,能被主进程读到呢?很简单,在主进程中在 read() 一次就可以了:
// 主进程,通过管道给子进程发送数据
foreach ($workers as $pid => $process) {
//向子进程管道里写内容:$process->write($data);
$process->write("hello worker[$pid]\n");
//从子进程管道里面读取信息:$process->read();
echo "From Worker: ".$process->read();
//第二次读
echo "From Worker: ".$process->read();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
再看下打印结果:
From Worker: From Master: hello worker[9328]
From Worker: hello master , this pipe is 4; this pid is 9328
From Worker: From Master: hello worker[9329]
From Worker: hello master , this pipe is 6; this pid is 9329
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
消息队列
swoole进程通信还有第二种方式就是“消息队列”,这个消息队列其实就是Linux系统里面的msgqueue
。
swoole提供了2个方法,来实现消息队列的通信。
pop() 和 push()
swoole深入学习 4. process的更多相关文章
- Swoole 入门学习(二)
Swoole 入门学习 swoole 之 定时器 循环触发:swoole_timer_tick (和js的setintval类似) 参数1:int $after_time_ms 指定时间[毫秒] ...
- swoole深入学习 8. 协程 转
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/yangyi2083334/article/ ...
- Swoole 简单学习(2)
Swoole 简单学习(2) swoole之tcp服务器: //创建tcp服务器new swoole_server(string $host,int $port,int $mode=SWOOLE_PR ...
- swoole深入学习 2. tcp Server和tcp Client
这节来学习Swoole最基础的Server和Client.会通过创建一个tcp Server来讲解. server <?php class Server { private $serv; pub ...
- swoole深入学习 1. swoole初始
0. 前言 swoole在PHP圈火了这么久,从2年前我用node写socket聊天服务器的时候就火了,那时候,经常有类似的文章php+swoole完爆nodejs之类的文章来吸引眼球,先不说它的好与 ...
- Swoole源代码学习记录(十三)——Server模块具体解释(上)
Swoole版本号:1.7.5-stable Github地址:https://github.com/LinkedDestiny/swoole-src-analysis 最终能够正式进入Server. ...
- Swoole源代码学习记录(十二)——ReactorThread模块
Swoole版本号:1.7.5-stable Github地址:https://github.com/LinkedDestiny/swoole-src-analysis 这一章将分析Swoole的Re ...
- Swoole 进程管理模块 Process 之单进程的使用
PHP 自带的 pcntl,存在很多不足,如: 没有提供进程间通信的功能: 不支持重定向标准输入和输出: 只提供了 fork 这样原始的接口,容易使用错误: Swoole\Process 提供了如下特 ...
- contiki学习笔记---process结构体
process,字面意义,进程,看看它的结构 struct process { struct process *next; #if PROCESS_CONF_NO_PROCESS_NAMES #def ...
随机推荐
- Ubuntu/Debian apt-get 404 Not Found Package Repository Errors,无法找到包的错误
最简单最常用的方法是,使用如下命令更新到新的版本: sudo apt-get dist-upgrade 但是这个方法有时候不一定能起作用,那么可以使用以下直接替换的命令: sudo sed -i -e ...
- openvpn用户管理、linux客户端配置及企业常用真实案例解析
1.给企业用户分配VPN账户的流程: 添加拨号需要密码的用户 # source vars NOTE: If you run ./clean-all, I will be doing a rm -rf ...
- windows下升级node&npm
一.升级npm npm install -g npm 二.升级node 1.查询node的安装目录 where node 2.在官网下载最新的安装包,直接覆盖安装即可. https://nodejs. ...
- visual studio 2017 installer 安装包制作过程出现的问题---此安装程序需要.NET Framework 版本 3.5,请安装该版本,然后重新运行此安装程序,可以从Web获得.NET Framework 。要立即做此事吗?
图一 visual studio 2017 installer 打包完成以后进行安装时,提示信息 “安装此安装程序需要.NET Framework 版本 3.5,请安装该版本,然后重新运行此安装程序, ...
- JavaScript对象简介(一)
本节介绍js的9个对象:Array数组对象 Boolean(true false) Date日前对象 Math 数学对象 Number 数字对象 String 字符串对象 RegExp 正则表达式对象 ...
- GuzzleHttp 请求设置超时时间
之前调用一个三方的 WEB API,大量的请求超时,导致 PHP 进程被占用完.整个网站一直报 504. 其中一个优化措施就是对三方 API 调用设置超时时间. use GuzzleHttp\Clie ...
- bzoj 1064 noi2008 假面舞会题解
莫名其妙的变成了我们的noip互测题... 其实这题思想还是比较简单的,只是分类不好分而已 其实就是一个dfs的事 首先,非常明显,原题目中的所有关系可以抽象成一个图(这是...显而易见的吧...) ...
- hdu 1372 骑士从起点走到终点的步数 (BFS)
给出起点和终点 求骑士从起点走到终点所需要的步数 Sample Inpute2 e4 //起点 终点a1 b2b2 c3a1 h8a1 h7h8 a1b1 c3f6 f6 Sample OutputT ...
- LYK loves graph(graph)
题目: LYK loves graph(graph) Time Limit:2000ms Memory Limit:128MB LYK喜欢花花绿绿的图片,有一天它得到了一张彩色图片,这张图片可以看 ...
- P1219 八皇后 含优化 1/5
题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序列2 4 6 1 3 ...