PHP 进程间通信——消息队列(msg_queue)
PHP 进程间通信——消息队列
本文不涉及PHP基础库安装。详细安装说明,请参考官网,或期待后续博客分享。
1、消息队列函数准备
<?php
//生成一个消息队列的key
$msg_key = ftok(__FILE__, 'a');
//产生一个消息队列
$msg_queue = msg_get_queue($msg_key, 0666);
//检测一个队列是否存在 ,返回boolean值
$status = msg_queue_exists($msg_key);
//可以查看当前队列的一些详细信息
$message_queue_status = msg_stat_queue($msg_queue);
//将一条消息加入消息队列
msg_send($msg_queue, 1, "Hello, 1");
msg_send($msg_queue, 1, 'Hello, 2');
msg_send($msg_queue, 1, "Hello, 3");
//从消息队列中读取一条消息。
msg_receive($msg_queue, 1, $message_type, 1024, $message1);
msg_receive($msg_queue, 1, $message_type, 1024, $message2);
msg_receive($msg_queue, 1, $message_type, 1024, $message3);
//移除消息队列
msg_remove_queue($msg_queue);
echo $message1.PHP_EOL;
echo $message2.PHP_EOL;
echo $message3.PHP_EOL;
/**
* msg_send 有三个必选参数
* resource $queue ,
* int $msgtype ,
* mixed $message
*
* 第一个必须要是队列资源类型。resource(4) of type (sysvmsg queue)
* 第二个参数是消息类型,一个整形,且必须大于0.
* msg_send() sends a message of type msgtype (which MUST be greater than 0) to the message queue specified by queue.
* 第三个参数。是要发送的信息。可以是字符串,也可以是数组。默认会被serialize.
*/
/**
* msg_receive 的参数比较多。必须要填的参数有5个。
* resource $queue ,
* int $desiredmsgtype ,
* int &$msgtype ,
* int $maxsize ,
* mixed &$message
*
* 其中$desiredmsgtype .经过测试和官网描述不符,暂不解释。
*
* $msgtype 。这个是msg_send 中所选定的msg_type.这是一个引用参数。
* The type of the message that was received will be stored in this parameter.
*
* $maxsize。
* The maximum size of message to be accepted is specified by the maxsize;
* if the message in the queue is larger than this size the function will fail (unless you set flags as described below).
* 这个参数声明的是一个最大的消息大小,如果超过则会报错。
*
* $message.
* 上文msg_send 发送的消息类型。
*/
2、多进程通信实例
<?php
/**
* 这段代码模拟了一个日常的任务。
* 第一个父进程产生了一个子进程。子进程又作为父进程,产生10个子进程。
* 可以简化为A -> B -> c,d,e... 等进程。
* 作为A来说,只需要生产任务,然后交给B 来处理。B 则会将任务分配给10个子进程来进行处理。
*
*/
//设定脚本永不超时
set_time_limit(0);
$ftok = ftok(__FILE__, 'a');
$msg_queue = msg_get_queue($ftok);
$pidarr = [];
//产生子进程
$pid = pcntl_fork();
if ($pid) {
//父进程模拟生成一个特大的数组。
$arr = range(1,100000);
//将任务放进队里,让多个子进程并行处理
foreach ($arr as $val) {
$status = msg_send($msg_queue,1, $val);
usleep(1000);
}
$pidarr[] = $pid;
msg_remove_queue($msg_queue);
} else {
//子进程收到任务后,fork10个子进程来处理任务。
for ($i =0; $i<10; $i++) {
$childpid = pcntl_fork();
if ($childpid) {
$pidarr[] = $childpid; //收集子进程processid
} else {
while (true) {
msg_receive($msg_queue, 0, $msg_type, 1024, $message);
if (!$message) exit(0);
echo $message.PHP_EOL;
usleep(1000);
}
}
}
}
//防止主进程先于子进程退出,形成僵尸进程
while (count($pidarr) > 0) {
foreach ($pidarr as $key => $pid) {
$status = pcntl_waitpid($pid, $status);
if ($status == -1 || $status > 0) {
unset($pidarr[$key]);
}
}
sleep(1);
}
?>
以上的示例只是为了说明多进程通信的应用示例,并未在真实的项目中应用。为了示例方便,省略了很多的校验条件。但作为了解过程及原理来说,并不影响。
在执行while 循环时候,必须要使用usleep(1000) 以上。否则CPU可能会被撑爆。
以上的多进程通信,没有产生僵尸进程。得益于最后一段的while循环。
其原理在于,父进程在每次循环的时候都检测子进程是否退出。如果退出,则父进程就会回收该子进程。并且将该进程从进程列表中删除。
可以使用ps aux |grep process.php来查看当前产生的进程数量。 其中process.php 是运行的文件名
效果如下:
[root@roverliang~]# ps aux |grep php
74:root 4163 9.3 2.2 243908 22844 pts/1 S+ 17:42 0:00 php process.php
75:root 4164 0.0 0.3 229104 3924 pts/1 S+ 17:42 0:00 php process.php
76:root 4165 1.3 0.4 229104 4124 pts/1 S+ 17:42 0:00 php process.php
77:root 4166 1.3 0.4 229104 4124 pts/1 S+ 17:42 0:00 php process.php
78:root 4167 1.0 0.4 229104 4124 pts/1 S+ 17:42 0:00 php process.php
79:root 4168 1.3 0.4 229104 4124 pts/1 S+ 17:42 0:00 php process.php
80:root 4169 1.3 0.4 229104 4124 pts/1 S+ 17:42 0:00 php process.php
81:root 4170 1.3 0.4 229104 4124 pts/1 S+ 17:42 0:00 php process.php
82:root 4171 1.3 0.4 229104 4124 pts/1 S+ 17:42 0:00 php process.php
83:root 4172 1.3 0.4 229104 4124 pts/1 S+ 17:42 0:00 php process.php
84:root 4173 1.3 0.4 229104 4124 pts/1 S+ 17:42 0:00 php process.php
85:root 4174 1.3 0.4 229104 4124 pts/1 S+ 17:42 0:00 php process.php
有疑问的话,可以共同讨论学习。博主也是刚学习这块,如果有什么不对的,希望能得到指点,共同提高。
本人博客所有文章,均为原创。部分文章中或引用相关资料,但均已著明来源出处。可随意转载、分享,但需加本文链接,以及版权说明。
【推广】
免费学中医,健康全家人
原文地址:https://www.cnblogs.com/lwrjiayou/p/6729196.html
- 推荐文章
- LA3266田忌赛马
- LA2678最短子序列
- LA2678最短子序列
- UVA11300分金币
- UVA11248 网络扩容(枚举割边扩充)
- UVA11248 网络扩容(枚举割边扩充)
- hdu3987 最小割边数
- UVA11419 我是SAM
- 创建多线程时,为何创建后需要Sleep?
- zoj3765
- java类集: collection, list , set, map
- 数独暴力遍历代码
- 【转】CentOS 编译安装MySQL全过程
- 【转】linux vi vim 的使用
- 【转】Linux安装JDK详细步骤
- 【转】Fatal server error:Server is already active
- 朋友圈卖课的人少了,知识付费缓解不了年轻人的焦虑
- 我替你们去了一趟魔都的Costco,差点死在那里
- 学习 Python 的 12 个方式
- Python 初学者常犯的5个错误
- 只需5分钟就能Get到的神器:Python虚拟环境安装&使用
- Linux——28年桌面进化史
- Linux使用Pidstat命令查看进程状态信息
- 提高思维能力的书籍推荐你看这本《决策必读12篇》
- 管理和自我管理:领导者自我管理的重要性
- 带团队看什么书 ?这本书教你提升团队凝聚力
- 基于RNN和CTC的语音识别模型,探索语境偏移解决之道
- 详解Spring中Bean的作用域与生命周期
- 物联网通信技术,那些你不知道的事
- 一招教你数据仓库如何高效批量导入与更新数据