PHP进程及进程间通信

一、引言

进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。换句话说就是,在系统调度多个cpu的时候,一个程序的基本单元。进程对于大多数的语言都不是一个陌生的概念,作为"世界上最好的语言PHP"当然也例外。

二、环境

php中的进程是以扩展的形式来完成。通过这些扩展,我们能够很轻松的完成进程的一系列动作。

  • pcntl扩展:主要的进程扩展,完成进程创建于等待操作。
  • posix扩展:完成posix兼容机通用api,如获取进程id,杀死进程等。
  • sysvmsg扩展:实现system v方式的进程间通信之消息队列。
  • sysvsem扩展:实现system v方式的信号量。
  • sysvshm扩展:实现system v方式的共享内存。
  • sockets扩展:实现socket通信。

这些扩展只能在linux/mac中使用,window下是不支持。最后建议php版本为5.5+。

三、简单的例子

一个简单的PHP多进程例子,该例子中,一个子进程,一个父进程。子进程输出5次,退出程序。

$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";
$childList = array();
$pid = pcntl_fork();
if ( $pid == -1) {// 创建失败exit("fork progress error!\n");
} else if ($pid == 0) {// 子进程执行程序$pid = posix_getpid();$repeatNum = 5;for ( $i = 1; $i <= $repeatNum; $i++) {echo "({$pid})child progress is running! {$i} \n";$rand = rand(1,3);sleep($rand);}exit("({$pid})child progress end!\n");
} else {// 父进程执行程序$childList[$pid] = 1;
}
// 等待子进程结束
pcntl_wait($status);
echo "({$parentPid})main progress end!";

完美,终于创建了一个子进程,一个父进程。完了么?没有,各个进程之间相互独立的,没有任何交集,使用范围严重受到现在。怎么办,哪就进程间通信(interprogress communication)呗。

四、进程间通信(IPC)

通常linux中的进程通信方式有:消息队列、信号量、共享内存、信号、管道、socket。

1.消息队列

消息队列是存放在内存中的一个队列。如下代码将创建3个生产者子进程,2个消费者子进程。这5个进程将通过消息队列通信。

$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";$childList = array();
// 创建消息队列,以及定义消息类型(类似于数据库中的库)
$id = ftok(__FILE__,'m');
$msgQueue = msg_get_queue($id);
const MSG_TYPE = 1;
// 生产者
function producer(){global $msgQueue;$pid = posix_getpid();$repeatNum = 5;for ( $i = 1; $i <= $repeatNum; $i++) {$str = "({$pid})progress create! {$i}";msg_send($msgQueue,MSG_TYPE,$str);$rand = rand(1,3);sleep($rand);}
}
// 消费者
function consumer(){global $msgQueue;$pid = posix_getpid();$repeatNum = 6;for ( $i = 1; $i <= $repeatNum; $i++) {$rel = msg_receive($msgQueue,MSG_TYPE,$msgType,1024,$message);echo "{$message} | consumer({$pid}) destroy \n";$rand = rand(1,3);sleep($rand);}
}
function createProgress($callback){$pid = pcntl_fork();if ( $pid == -1) {// 创建失败exit("fork progress error!\n");} else if ($pid == 0) {// 子进程执行程序$pid = posix_getpid();$callback();exit("({$pid})child progress end!\n");}else{// 父进程执行程序return $pid;}
}
// 3个写进程
for ($i = 0; $i < 3; $i ++ ) {$pid = createProgress('producer');$childList[$pid] = 1;echo "create producer child progress: {$pid} \n";
}
// 2个写进程
for ($i = 0; $i < 2; $i ++ ) {$pid = createProgress('consumer');$childList[$pid] = 1;echo "create consumer child progress: {$pid} \n";
}
// 等待所有子进程结束
while(!empty($childList)){$childPid = pcntl_wait($status);if ($childPid > 0){unset($childList[$childPid]);}
}
echo "({$parentPid})main progress end!\n";

由于消息队列去数据是,只有一个进程能去到,所以不需要额外的锁或信号量。

2. 信号量与共享内存

信号量:是系统提供的一种原子操作,一个信号量,同时只有你个进程能操作。一个进程获得了某个信号量,就必须被该进程释放掉。

共享内存:是系统在内存中开辟的一块公共的内存区域,任何一个进程都可以访问,在同一时刻,可以有多个进程访问该区域,为了保证数据的一致性,需要对该内存区域加锁或信号量。

以下,创建多个进程修改内存中的同一个值。

$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";
$childList = array();// 创建共享内存,创建信号量,定义共享key
$shm_id = ftok(__FILE__,'m');
$sem_id = ftok(__FILE__,'s');
$shareMemory = shm_attach($shm_id);
$signal = sem_get($sem_id);
const SHARE_KEY = 1;
// 生产者
function producer(){global $shareMemory;global $signal;$pid = posix_getpid();$repeatNum = 5;for ( $i = 1; $i <= $repeatNum; $i++) {// 获得信号量sem_acquire($signal);if (shm_has_var($shareMemory,SHARE_KEY)){// 有值,加一$count = shm_get_var($shareMemory,SHARE_KEY);$count ++;shm_put_var($shareMemory,SHARE_KEY,$count);echo "({$pid}) count: {$count}\n";}else{// 无值,初始化shm_put_var($shareMemory,SHARE_KEY,0);echo "({$pid}) count: 0\n";}// 用完释放sem_release($signal);$rand = rand(1,3);sleep($rand);}
}
function createProgress($callback){$pid = pcntl_fork();if ( $pid == -1) {// 创建失败exit("fork progress error!\n");} else if ($pid == 0) {// 子进程执行程序$pid = posix_getpid();$callback();exit("({$pid})child progress end!\n");}else{// 父进程执行程序return $pid;}
}
// 3个写进程
for ($i = 0; $i < 3; $i ++ ) {$pid = createProgress('producer');$childList[$pid] = 1;echo "create producer child progress: {$pid} \n";
}
// 等待所有子进程结束
while(!empty($childList)){$childPid = pcntl_wait($status);if ($childPid > 0){unset($childList[$childPid]);}
}
// 释放共享内存与信号量
shm_remove($shareMemory);
sem_remove($signal);
echo "({$parentPid})main progress end!\n";

3.信号

信号是一种系统调用。通常我们用的kill命令就是发送某个信号给某个进程的。具体有哪些信号可以在liunx/mac中运行kill -l查看。下面这个例子中,父进程等待5秒钟,向子进程发送sigint信号。子进程捕获信号,掉信号处理函数处理。

$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";// 定义一个信号处理函数
function sighandler($signo) {$pid = posix_getpid();echo "{$pid} progress,oh no ,I'm killed!\n";exit(1);
}$pid = pcntl_fork();
if ( $pid == -1) {// 创建失败exit("fork progress error!\n");
} else if ($pid == 0) {// 子进程执行程序// 注册信号处理函数declare(ticks=10);pcntl_signal(SIGINT, "sighandler");$pid = posix_getpid();while(true){echo "{$pid} child progress is running!\n";sleep(1);}exit("({$pid})child progress end!\n");
}else{// 父进程执行程序$childList[$pid] = 1;// 5秒后,父进程向子进程发送sigint信号.sleep(5);posix_kill($pid,SIGINT);sleep(5);
}
echo "({$parentPid})main progress end!\n";

4.管道(有名管道)

管道是比较常用的多进程通信手段,管道分为无名管道与有名管道,无名管道只能用于具有亲缘关系的进程间通信,而有名管道可以用于同一主机上任意进程。这里只介绍有名管道。下面的例子,子进程写入数据,父进程读取数据。

// 定义管道路径,与创建管道
$pipe_path = '/data/test.pipe';
if(!file_exists($pipe_path)){if(!posix_mkfifo($pipe_path,0664)){exit("create pipe error!");}
}
$pid = pcntl_fork();
if($pid == 0){// 子进程,向管道写数据$file = fopen($pipe_path,'w');while (true){fwrite($file,'hello world');$rand = rand(1,3);sleep($rand);}exit('child end!');
}else{// 父进程,从管道读数据$file = fopen($pipe_path,'r');while (true){$rel = fread($file,20);echo "{$rel}\n";$rand = rand(1,2);sleep($rand);}
}

5.socket

socket即我们常说的套接字编程。这个待补充。

转载于:https://www.cnblogs.com/aksir/p/6777671.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/370912.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

福州java培训哪里好_南通java培训哪家好

渡课IT教育成立于2006年&#xff0c;14年来&#xff0c;我们累计输送学员达 6000 &#xff0c;其中南通地区输送50%&#xff0c;上海 40%&#xff0c;其他地区 10%&#xff0c;学员1年后的平均薪水达 9860 元&#xff1b;受到1000用人单位的赞誉与支持。Java开发的需求量在北上…

Linux 服务器注意事项

1.创建时 数据文件一定分盘挂载 2.LVM 虚拟磁盘卷是否创建 有争议&#xff1f;&#xff1f;&#xff1f;3.hosts 文件 最好添加本机映射 主机名 127.0.0.1 4.iptables 开启转载于:https://www.cnblogs.com/centos2017/p/7896681.html

linux 查看下挂磁盘,linux下磁盘挂载与查看

df查看系统分区和使用情况使用方法&#xff1a;df-h(自动按照大小做单位适应显示)df-i(查看iNode使用情况)free查看..LABELdefaults默认选项&#xff1a;rw (可读写)sudi (加此选项后则该分区可为文件加s权限&#xff1b;如不需要则写为nosuid)dev(可以解析该分区下的块…

研究僵局–第2部分

调查死锁时最重要的要求之一就是要研究死锁。 在我的上一个博客中&#xff0c;我编写了一个名为DeadlockDemo代码&#xff0c;该代码使用一堆线程在一系列银行帐户之间转移随机数&#xff0c;然后陷入僵局。 该博客运行该代码以演示获取线程转储的几种方法。 线程转储只是一个…

从0开始接触html--第一天学习内容总结

第一天 总结: h1-h6 p 段落 hr br有序 ol li 无序 ul li 定义列表 dl dt dd块级元素&#xff1a;独占一行&#xff0c;h1-h6 p hr div行内元素&#xff1a;共占一行, em和i strong和b u del和s span块级分区元素&#xff1a;div header nav article footer行内分区元素&#…

连锁便利店管理系统有什么用

连锁便利店管理系统对于连锁便利店的运营和管理非常有用。以下是一些常见的用途&#xff1a; 1. 库存管理&#xff1a;连锁便利店通常需要管理多个门店的库存&#xff0c;管理系统可以帮助实时掌握各个门店的库存情况&#xff0c;包括商品数量、进货记录、库存调拨等。这样可以…

经常使用meta标签属性

《meta》 1.Keywords (keyword)说明&#xff1a;告诉搜索引擎你网页的keyword是什么。 使用方法&#xff1a;<meta name"keywords" content"SEO优化,SEO优化教程,站点优化,搜索引擎优化教程"> 2. Description (网页描写叙述)说明&#xff1a;Descrip…

浏览器打印设置横向打印_爱普生打印机无线连接设置

1、首先&#xff0c;把epsonl385打印机插上电源通电&#xff0c;待自检完成后&#xff0c;便可以设置。如果用户家里的无线路由器带有WPS(Wi-Fi Protected Setup)或QSS(又称快速安全设置)功能&#xff0c;那就简单多了。2、通过WPS或QSS无线路由器按钮连接&#xff0c;给无线路…

linux python定时任务调度,Python下定时任务框架APScheduler的使用

1.APScheduler简介&#xff1a;APScheduler是Python的一个定时任务框架&#xff0c;可以很方便的满足用户定时执行或者周期执行任务的需求&#xff0c;它提供了基于日期date、固定时间间隔interval 、以及类似于Linux上的定时任务crontab类型的定时任务。并且该框架不仅可以添加…

图片和文件上传js剖析

/** * 商户资质信息模块js * * 涉及页面组件 { * 上传组件&#xff08;UploadFileComponent&#xff09; * } * * * 初始化工具&#xff08;init&#xff09; * * Author:Waver */var qualificationInfoModule (function() { // 上传文件类型 var UPLOAD_FILE_TYPE…

研究僵局–第1部分

我敢肯定我们都去过那里&#xff1a;太晚了&#xff0c;您饿了&#xff0c;服务器已挂起&#xff0c;或者应用程序正在以蜗牛的速度运行&#xff0c;并且有人喘着气想要您解决问题&#xff0c;然后再去解决。 您的应用程序意外挂起的可能原因之一是称为死锁的线程问题。 无需赘…

前端的学习之旅

Html学习笔记1 特殊符号&#xff1a;html中对换行缩进空格不敏感&#xff0c;都只会解析成一个空格 空格&#xff1a; < : < > :$gt; 版权符号&#xff1a;&copy&#xff1b; 表格&#xff1a;1 表示表格&#xff1a;table表示表格 tr&#xff1a;…

使用Vue.js和Axios从第三方API获取数据 — SitePoint

更多的往往不是&#xff0c;建立你的JavaScript应用程序时&#xff0c;你会想把数据从远程源或消耗一个[ API ]&#xff08;https&#xff1a;/ /恩。维基百科。org /维基/ application_programming_interface&#xff09;。我最近看了一些[公开]&#xff08;https://github.co…

区位码怎么知道点阵里的起始点_自身免疫疾病的GAPS起始饮食改良版

写这篇文章的原因如果您已经关注我的博客一段时间&#xff0c;您知道我开始使用GAPS饮食&#xff0c;然后转换到AIP饮食&#xff0c;因为我仍在努力治疗炎症和自身免疫的发作。 Katy Haldiman 有同样的经历&#xff0c;我们并不孤单。许多患有自身免疫性疾病的人在 GAPS 上挣扎…

Linux存储保护,谈谈Linux中的存储保护

谈谈Linux中的存储保护以下讨论的内容是以i386平台为基础的Linux将4G的地址划分为用户空间和内核空间两部分。在Linux内核的低版本中(2。0。X)&#xff0c;通常0-3G为用户空间&#xff0c;3G-4G为内核空间。这个分界点是可以可以改动的。正是这个分界点的存在&#xff0c;限制了…

004-JQuery属性

添加与删除属性CSS类HTML代码/文本/值添加与删除属性 attr(name|properties|key,value|fn) &#xff1a;设置或返回被选元素的属性值 removeAttr(name) &#xff1a;从每一个匹配的元素中删除name属性 prop(name|properties|key,value|fn) &#xff1a;获取在匹配的元素集中的第…

预热您的JVM –超快速生产服务器和IDE

几个月前&#xff0c;我正在阅读Java中的复杂事件处理以及实现低延迟的方法。 在我长达一个小时的研究结束时&#xff0c;我发现即使您的应用程序编写正确并且您的方法主要在0&#xff08;log n&#xff09;的时间内运行&#xff0c;并且您正在使用某些前沿的硬件解决方案&…

微信小程序APP(商超营销类)经验总结

项目介绍 这是一款主打门店营销的小程序。包括首页、门店、营销、个人设置、登录、数据统计展示、营销设置等。 本来要独立完成整个项目&#xff0c;包括前后端一套的&#xff0c;有些意外因素&#xff0c;项目临时收尾&#xff08;说明&#xff1a;只完成了前端的部分&#…

excel不显示0_Excel数字过长不能完整显示?超长数字变为0

Excel中计算规则和限制设定数值精确度为15位&#xff01;超过15位后&#xff0c;数字会显示为0excel数字超过15位&#xff0c;会显示为0&#xff0c;超过10位&#xff0c;默认采用科学计数法显示1、如何解决超长数字输入&#xff0c;全部显示问题&#xff1f;&#xff08;单元格…

Android天气预报设计

——嵌入式软件开发 名字功能模块代码行数备注谢灿辉Widget200桌面小程序李杨敏GPS定位&#xff0c;百度地图API100-150获取当前所在城市丁小芳城市选择Activity&#xff0c;天气API获取天气100-200包括数据库交互本软件是一个天气类应用软件&#xff0c;带有widget&#xff0c…