当前位置:首页 > 教育

wifexited php多进程编程详解

如果对手机阅读不满意,可以直接点击左下角阅读原文。前言

php单进程中的问题:

多核处理器利用不足,而单处理器通常需要等待其他操作完成后才能继续工作。任何现代操作系统都可以在幕后进行多任务处理,这意味着在短时间内,一台计算机可以调度多个进程来执行多个程序。

如果我们把所有的工作都局限在一个进程上,那么它一次只能做一件事,也就是说我们需要把单进程任务变成多进程任务,这样才能利用操作系统的多任务处理能力。

多进程和多线程

在继续之前,解释一下多重处理和多线程的区别。

进程是程序的唯一实例,有自己的内存空,自己的进程ID号等。

一个线程可以看作一个虚拟进程,它没有自己的进程ID,也没有自己的内存空,但是仍然可以使用多任务。

启用超线程的CPU可以通过动态生成线程来进一步前进,以尽可能避免延迟。

虽然可能有人不同意,但大多数Unix程序员对线程都有一定程度的不信任。Unix系统总是更喜欢多进程,然后是多线程,部分原因是在Unix上创建一个进程(通常称为子进程的“生成”或“分支”)非常快。在其他操作系统中,比如Windows,fork比较慢,所以线程概念比较流行。

考虑到这一点,目前只在unix系统中支持php分叉多个进程就不足为奇了。这个扩展是pcntl_fork函数

如何用php做多进程编程

用pcntl_fork扩展函数在php中执行frok多个进程。

Pcntl_fork返回值描述

当调用pcntl_fork函数时,它将返回3个值。

如果返回值为-1,fork失败,并且没有子进程。这可能是因为内存不足,或者是因为已经达到系统对用户进程数量的限制。

如果返回值为大于0的任意数字,则当前脚本为调用pcntl_fork()的父进程,返回值为分叉子进程的进程ID(PID)。最后,如果返回值为0,则当前脚本是分叉的子节点。

pcntl_fork的执行原理

如果成功执行了pcntl_fork()函数,PHP的两个副本将同时执行同一个脚本。它们都继续从pcntl_fork()行执行,最重要的是,子进程获得父进程中设置的所有变量的副本,甚至资源。我们忘记的一个关键是,资源的副本不是一个独立的资源,它们会指向同一个东西,这可能是有问题的。更多细节将在后面讨论。

下面是使用pcntl_fork()的一个基本例子:

& lt?PHP $ PID = pcntl _ fork();开关($pid) { case-1: print "无法分叉!n ";退出;案例0:打印“在孩子身上!n ";打破;默认:打印“在父母!n ";}?>。

上面的脚本只是在父进程和子进程中打印一条消息。但是,它没有显示父项的变量数据是如何复制到子项的。它输出两条信息,如下所示,表明已经有两个进程在执行(一个是主进程,另一个是来自fork的子进程)

[root @ 25f 0b 49 DC 696 wwwroot]# PHP fork.php Inparent!儿童!

然后看下面的例子:

& lt?PHP $ PID 1 = pcntl _ fork();//fork$pid2 = pcntl_fork()第一次;//第二个fork $ PID 3 = pcntl _ fork();//第三个fork $ current _ process _ id = POSIX _ getpid();echo " current _ process _ id = = $ current _ process _ id = = = PID 1 = = $ PID 1 = = = PID 2 = = $ PID 2 = = PID 3 = = $ PID 3n ";

在上例中,输出结果如下:

current _ process _ id = = = 13090 = = = PID 1 = = 13091 = = = PID 2 = = = 13092 = = PID 3 = = 13093 current _ process _ id = = = 13093 = = = PID 1 = = 13091 = = = PID 2 = = = 13092 = = PID 3 = = 0 current _ pro _ cess _ id = = = 13092 = = = PID 1 = = 13091 = = = PID 2 = =

分析以上结果,

可以看出主进程ID是13090

第一次,叉子

主13090->: 13091

第二次,叉子

主13090->: 13092

孩子13091->: 13095

第三次,叉子

主13090->: 13093

孩子13091->: 13096

孩子13092->: 13094

孩子13095->: 13097

到目前为止,共有8个进程正在执行当前脚本

然后看下面的例子:

& lt?PHP $ main _ process _ id = POSIX _ getpid();echo "主进程id = = $ main _ process _ IDN ";for($ I = 1;$i <。= 5;++ $ I){ $ PID = pcntl _ fork();$ current _ process _ id = POSIX _ getpid();if(!$pid) { echo "child $i当前进程id = = $ current _ process _ id = = PID = = $ pidn ";睡眠(1);//sleep($i)打印“In child $ In”;//这里设置睡眠不会阻塞输出,1s后会自动结束进程。//睡眠(1);//结束当前子进程,不要让子进程继续forkexit,也不会阻止父进程继续forkexit} else{ echo "父当前进程id = = $ current _ process _ id = = PID = = $ pidn ";打印“在父$ In”;//fork完成后退出父进程,不参与fork//退出时间,可以保证执行顺序,但是下一个fork要等到子进程执行完毕才能分叉。//退出;} }

这一次,fork成功地创建了五个子进程,因为每个子进程在父进程最终设置时都获得了$ i变量的副本,所以脚本打印出了“inchild1”、“inchild2”、“inchild3”、“inchild4”和“inchild5”。

[根@ 25f 0b 49 DC 696 wwwroot]# PHP fork2.php主进程d== 13163父当前进程= = 13163 = = pid = = 13164Inparent父当前进程= = 13163 = = pid = = 13165Inparent父当前进程= = 13163 = = pid = = 13166Inparent父当前进程d== 13163==pid==

但是,一切都不是那么简单,因为运行上面的脚本有两个关键要注意。

首先,请注意每个子脚本调用在打印出它的消息后退出。在正常情况下,这将立即退出脚本,但这里它退出的是子PHP脚本,而不是父脚本或任何其他子脚本。因此,每隔一个子脚本和父脚本可以并且确实在一个子脚本终止后继续执行。

其次,当脚本运行时,它的输出可能会令人困惑。

注意孩子如何按顺序打印出自己的信息。虽然这可能很常见,但你不能指望你的孩子按照特定的顺序被处决。

这是多处理器的基本原理之一:一旦产生了一个进程,就由操作系统来决定何时执行它,给多少时间。

还要注意我是如何立即返回我的shell提示符,然后叫五个孩子打印出他们的消息的,虽然我显然有控制权。

之所以这样,是因为孩子虽然依附于终端,但基本都是在后台运行。一旦父程序终止,命令提示符会重新出现,您可以开始执行其他程序,但是正如您所看到的,子程序在思考时仍然是活动的(因为子程序做不到)。如果没有sleep命令,这一点就不那么明显了,但重要的是要记住,子进程本质上有自己的运行环境。

PHP和任何家长一样,可以让他们监控孩子,确保他们做的事情是正确的。这是通过两个新功能实现的:

Pcntl_waitpid(),指示PHP等待子进程。

Pcntl_wexitstatus(),它获取终止子进程返回的值。我们已经看到了exit()函数以及如何使用它向系统返回值

我们将使用该值将该值发送回父进程,然后使用pcntl_wexitstatus()检索它。

在进入代码之前,让我解释一下这些新函数是如何使用的。

pcntl_waitpid

int pcntl_waitpid ( int $pid,int & amp$status [,int $options = 0 ])

默认情况下,pcntl_waitpid()将导致父进程无限期挂起,等待子进程终止。

如果在调用此函数时,pid指定的子进程已经退出(通常称为僵尸进程),此函数将立即返回

至少需要两个参数,$pid-父类应该等待的子进程标识,$status-用于填充子进程状态的变量

$pid的值可以是下列值之一:

& lt-1等待任何进程组ID等于参数p ID给定的绝对值的进程。例如,如果传递-1802,pcntl_waitpid将等待任何进程组标识为1802的子进程。-1等待任何子进程;与pcntl_wait函数行为相同。0等待与调用进程组具有相同标识的任何子进程。这是最常用的值。>。0等待进程号等于参数pid值的子进程。也就是说,如果您传入1802,pcntl_waitpid将等待子进程1802终止。

$状态

Pcntl_waitpid()将存储状态参数的状态信息。状态参数返回的状态信息可以使用以下功能:pcntl _ wifexisted(),pcntl _ wifstopped(),pcntl _ wifsignaled(),pcntl _ wet status(),pcntl_wstopsig()和pcntl

返回值

Pcntl_waitpid()返回退出的子进程的进程号,出错时返回-1。

返回终止子进程的PID,然后用状态变量填充子进程的退出信息。

如果调用了pcntl_waitpid,并且没有子运行,则立即返回-1,并且不填充状态变量。

因此,如果将0作为第一个参数传递给函数,pcntl_waitpid()将等待其任何子进程终止。建立后,返回子进程的PID,终止并填充第二个参数,提供终止子进程的信息。因为我们有几个孩子,我们需要继续调用pcntl_waitpid(),直到它返回-1。每次有东西返回,都要打印出子进程的返回值。

从我们的子进程返回一个值就像将一个参数传递给exit()一样简单,而不仅仅是终止。这将通过pcntl_waitpid()的返回值返回带有状态代码的父节点。此状态代码不直接作为返回值计算,因为它包含两位信息:子节点如何终止,如果子节点终止,则返回其退出代码。

现在我们只假设子节点自己终止,这意味着退出代码总是设置在pcntl_waitpid()的返回值中。若要从返回值中提取退出代码,请使用pcntl_wexitstatus()函数,该函数将返回值作为其唯一参数,并返回子进程的退出代码。

这听起来可能很复杂,但是一旦你看了下一个代码项目,它就应该变得清晰了。这个例子展示了我们讨论的所有内容:

& lt?PHP for($ I = 1;$i <。= 5;++ $ I){ $ PID = pcntl _ fork();if(!$ PID){ sleep(1);$ current _ process _ id = POSIX _ getpid();打印“In child $ I = = = process _ id = = $ current _ process _ IDN”;出口($ I);} } while($ PID = pcntl _ wait PID(0,$status))!=-1){ $ status = pcntl _ wexi status($ status);echo“子$ status completed = = PID = = $ pidn”;}?>。

上面的示例输出并验证pcntl_waitpid返回的pid是否正确

in child 1 = = = process _ id = = = 13106 Inchild 5 = = = process _ id = = = 13110 Inchild 4 = = = process _ id = = = 13109 Inchild 3 = = = process _ id = = = 13108 Inchild 2 = = = process _ id = = = 1 3107 child 4 completed = = PID = = 13109 child 5 completed = = PID = = 13110 child 1 completed = = PID

请注意,通过使用exit($ I);每个子节点返回打印在屏幕上的数字作为退出代码。main while循环再次调用pcntl_waitpid(),直到它返回-1(没有子节点),对于每个终止的子节点,它使用pcntl_wexitstatus()提取退出代码并将其打印出来。请注意,pcntl_waitpid()的第一个参数是0,这意味着它将等待所有子级。

运行脚本应该停止命令提示符,直到所有五个子命令都终止,这是理想的。

关注微信微信官方账号:PHP技术全集

PHPer升级成大神不难!

1.《wifexited php多进程编程详解》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。

2.《wifexited php多进程编程详解》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。

3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/jiaoyu/808346.html

上一篇

宽脚和瘦脚的对比照片 7张图告诉你胖子与瘦子的区别!看完千万别哭!

下一篇

岳云鹏女儿 岳云鹏辅导女儿作业到崩溃!师兄弟下场“补刀”,他又被嘲笑了

内邱贴吧 痛心!内丘走失3岁小女孩已证实溺亡!隆尧人都看好自己的孩子吧!

  • 内邱贴吧 痛心!内丘走失3岁小女孩已证实溺亡!隆尧人都看好自己的孩子吧!
  • 内邱贴吧 痛心!内丘走失3岁小女孩已证实溺亡!隆尧人都看好自己的孩子吧!
  • 内邱贴吧 痛心!内丘走失3岁小女孩已证实溺亡!隆尧人都看好自己的孩子吧!

易牙 最残忍的美食记录,易牙烹子,亲手煮了自己的儿子只为拍马屁

  • 易牙 最残忍的美食记录,易牙烹子,亲手煮了自己的儿子只为拍马屁
  • 易牙 最残忍的美食记录,易牙烹子,亲手煮了自己的儿子只为拍马屁
  • 易牙 最残忍的美食记录,易牙烹子,亲手煮了自己的儿子只为拍马屁

张恒郑爽男友 事情开始反转?郑爽发文控诉前男友张恒出轨,肯定孩子是自己的!

  • 张恒郑爽男友 事情开始反转?郑爽发文控诉前男友张恒出轨,肯定孩子是自己的!
  • 张恒郑爽男友 事情开始反转?郑爽发文控诉前男友张恒出轨,肯定孩子是自己的!
  • 张恒郑爽男友 事情开始反转?郑爽发文控诉前男友张恒出轨,肯定孩子是自己的!
贝西克塔斯 伊尔马兹:当年去国安是自己的选择 希望胡尔克加盟贝西克塔斯

贝西克塔斯 伊尔马兹:当年去国安是自己的选择 希望胡尔克加盟贝西克塔斯

1月23日直播。在接受土耳其媒体“ntvspor”采访时,前国家安全外援伊尔马兹表达了他对胡尔克和他的老东家贝西克塔斯之间传闻的看法,希望胡尔克能在贝西克塔斯踢球。回顾他在中国踢球的决定,伊尔马兹说:“从加拉塔萨雷来中国是我的选择。自从被马尼萨送走后,我这辈子从来没...

蒙托利沃 蒙托利沃:告别米兰是痛苦的,但是我在米兰留下了自己的一部分

蒙托利沃 蒙托利沃:告别米兰是痛苦的,但是我在米兰留下了自己的一部分

1月23日直播。在接受意大利日报空体育记者采访时,前米兰队长蒙托利沃谈到了他对米兰的热爱。蒙托利沃说:“告别米兰是痛苦的,但我在米兰留下了自己的一部分。我职业生涯的最后一场比赛是在亚特兰大的蓝色竞技场上演的,我也在那里上演了我的职业生涯处子秀。”“事业走到最后我觉得...

用英语介绍自己的学校 学校英语面试自我介绍怎么准备?

  • 用英语介绍自己的学校 学校英语面试自我介绍怎么准备?
  • 用英语介绍自己的学校 学校英语面试自我介绍怎么准备?
  • 用英语介绍自己的学校 学校英语面试自我介绍怎么准备?

有效率的英语 如何每天只用10分钟,来有效提高自己的英语水平?

  • 有效率的英语 如何每天只用10分钟,来有效提高自己的英语水平?
  • 有效率的英语 如何每天只用10分钟,来有效提高自己的英语水平?
  • 有效率的英语 如何每天只用10分钟,来有效提高自己的英语水平?

温碧霞年龄 一辈子不换风格,54岁温碧霞活成了自己的公主

  • 温碧霞年龄 一辈子不换风格,54岁温碧霞活成了自己的公主
  • 温碧霞年龄 一辈子不换风格,54岁温碧霞活成了自己的公主
  • 温碧霞年龄 一辈子不换风格,54岁温碧霞活成了自己的公主