资讯专栏INFORMATION COLUMN

PHP多进程初探 --- 开篇

snowell / 301人阅读

摘要:所以我们只说的多进程,至于多线程就暂时放到一边儿。出来新进程则成为子进程,原进程则成为父进程,子进程拥有父进程的副本。在父进程中返回子进程的进程,在子进程内部本身返回数字。

[原文地址:https://blog.ti-node.com/blog...]

实际上PHP是有多线程的,只是很多人不常用。使用PHP的多线程首先需要下载安装一个线程安全版本(ZTS版本)的PHP,然后再安装pecl的pthread扩展。

实际上PHP是有多进程的,有一些人再用,总体来说php的多进程还算凑合,只需要在安装PHP的时候开启pcntl模块(是不是跟UNIX中的fcntl有点儿.... ....)即可。在*NIX下,在终端命令行下使用php -m就可以看到是否开启了pcntl模块。

所以我们只说php的多进程,至于php多线程就暂时放到一边儿。

注意:不要在apache或者fpm环境下使用php多进程,这将会产生不可预估的后果。

进程是程序执行的实例,举个例子有个程序叫做 “ 病毒.exe ”,这个程序平时是以文件形式存储在硬盘上,当你双击运行后,就会形成一个该程序的进程。系统会给每一个进程分配一个唯一的非负整数用来标记进程,这个数字称作进程ID。当该进程被杀死或终止后,其进程ID就会被系统回收,然后分配给新的其余的进程。

说了这么多,这鬼东西有什么用吗?我平时用CI、YII写个CURD跟这个也没啥关联啊。实际上,如果你了解APACHE PHP MOD或者FPM就知道这些东西就是多进程实现的。以FPM为例,一般都是nginx作为http服务器挡在最前面,静态文件请求则nginx自行处理,遇到php动态请求则转发给php-fpm进程来处理。如果你的php-fpm配置只开了5个进程,如果处理任意一个用户的请求都需要1秒钟,那么5个fpm进程1秒中就最多只能处5个用户的请求。所以结论就是:如果要单位时间内干活更快更多,就需要更多的进程,总之一句话就是多进程可以加快任务处理速度。

在php中我们使用pcntl_fork()来创建多进程(在*NIX系统的C语言编程中,已有进程通过调用fork函数来产生新的进程)。fork出来新进程则成为子进程,原进程则成为父进程,子进程拥有父进程的副本。这里要注意:

子进程与父进程共享程序正文段

子进程拥有父进程的数据空间和堆、栈的副本,注意是副本,不是共享

父进程和子进程将继续执行fork之后的程序代码

fork之后,是父进程先执行还是子进程先执行无法确认,取决于系统调度(取决于信仰)

这里说子进程拥有父进程数据空间以及堆、栈的副本,实际上,在大多数的实现中也并不是真正的完全副本。更多是采用了COW(Copy On Write)即写时复制的技术来节约存储空间。简单来说,如果父进程和子进程都不修改这些 数据、堆、栈 的话,那么父进程和子进程则是暂时共享同一份 数据、堆、栈。只有当父进程或者子进程试图对 数据、堆、栈 进行修改的时候,才会产生复制操作,这就叫做写时复制。

在调用完pcntl_fork()后,该函数会返回两个值。在父进程中返回子进程的进程ID,在子进程内部本身返回数字0。由于多进程在apache或者fpm环境下无法正常运行,所以大家一定要在php cli环境下执行下面php代码。

第一段代码,我们来说明在程序从pcntl_fork()后父进程和子进程将各自继续往下执行代码:

 0 ){
          echo "我是父亲".PHP_EOL;
        } else if( 0 == $pid ) {
          echo "我是儿子".PHP_EOL;
        } else {
          echo "fork失败".PHP_EOL;
        }

将文件保存为test.php,然后在使用cli执行,结果如下图所示:

第二段代码,用来说明子进程拥有父进程的数据副本,而并不是共享:

 0 ){
          $number += 1;
          echo "我是父亲,number+1 : { $number }".PHP_EOL;
        } else if( 0 == $pid ) {
          $number += 2;
          echo "我是父亲,number+2 : { $number }".PHP_EOL;
        } else {
          echo "fork失败".PHP_EOL;
        }

第三段代码,比较容易让人思维混乱,pcntl_fork()配合for循环来做些东西,问题来了:会显示几次 “ 儿子 ”?

 0 ){
               // do nothing ...
            } else if( 0 == $pid ){
                echo "儿子".PHP_EOL;
            }
        }

上面代码执行结果如下:

仔细数数,竟然是显示了7次 “ 儿子 ”。好奇怪,难道不是3次吗?... ...
下面我修改一下代码,结合下面的代码,再思考一下为什么会产生7次而不是3次。

 0 ){
               // do nothing ...
            } else if( 0 == $pid ){
                echo "儿子".PHP_EOL;
                exit;
            }
        }

执行结果如下图所示:

前面强调过:父进程和子进程将继续执行fork之后的程序代码。这里就不解释,实在想不明白的,可以动手自己画画思考一下。

为了避免写成臭尾理论文儿,这里强行断篇分割一下,下一章说僵尸进程和孤儿进程的一些恩怨情仇。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/33587.html

相关文章

  • PHP进程初探 --- 开篇

    摘要:所以我们只说的多进程,至于多线程就暂时放到一边儿。出来新进程则成为子进程,原进程则成为父进程,子进程拥有父进程的副本。在父进程中返回子进程的进程,在子进程内部本身返回数字。 [原文地址:https://blog.ti-node.com/blog...] 实际上PHP是有多线程的,只是很多人不常用。使用PHP的多线程首先需要下载安装一个线程安全版本(ZTS版本)的PHP,然后再安装pec...

    wh469012917 评论0 收藏0
  • PHP socket初探 --- 颤颤抖抖开篇libevent(一)

    摘要:原文地址正如标题所言,颤颤抖抖开篇。于是只能是你自己,把单子上的个快递逐次和收到的对比一遍,然后对比完毕后再把这个单子给了阿梅,然后阿梅继续等。剃光头前的阿梅,就是,不敢正眼看老板娘一眼。剃光头后的阿梅,就是,可徒手接魔鬼队的死亡之球。 [原文地址:https://blog.ti-node.com/blog...] 正如标题所言,颤颤抖抖开篇epoll。颤颤抖抖的原因大概也就是以前几乎...

    levinit 评论0 收藏0
  • PHP进程初探 --- 利用进程开发点儿东西吧

    摘要:主进程退出子进程继续执行给进程重新起个名字加入我们出个子进程就可以搞定这些任务,那么出个子进程,同时父进程要负责这个子进程的状态等。 [原文地址:https://blog.ti-node.com/blog...] 干巴巴地叨逼叨了这么久,时候表演真正的技术了! 做个高端点儿的玩意吧,加入我们要做一个任务系统,这个系统可以在后台帮我们完成一大波(注意是一大波)数据的处理,那么我们自然想到...

    huaixiaoz 评论0 收藏0
  • PHP进程初探 --- 孤儿和僵尸

    摘要:孤儿进程是指父进程在出子进程后,自己先完了。这个问题很尴尬,因为子进程从此变得无依无靠无家可归,变成了孤儿。在中,父进程对子进程的状态收集等是通过和等完成的。这个函数返回退出的子进程的进程或者失败返回。 [原文地址:https://blog.ti-node.com/blog...] 实际上,你们一定要记住:PHP的多进程是非常值得应用于生产环境具备高价值的生产力工具。 但我认为在正式开...

    xialong 评论0 收藏0
  • PHP进程初探 --- 进程间通信二三事

    摘要:多进程通信之一命名管道。多进程通信之三信号量与共享内存。共享内存是最快是进程间通信方式,因为个进程之间并不需要数据复制,而是直接操控同一份数据。的一些书籍中甚至不建议新手轻易使用这种进程间通信的方式,因为这是一种极易产生死锁的解决方案。 [原文地址:https://blog.ti-node.com/blog...] 往往开启多进程的目的是为了一起干活加速效率,前面说了不同进程之间的内存...

    CollinPeng 评论0 收藏0

发表评论

0条评论

snowell

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<