UDN-企业互联网技术人气社区

板块导航

浏览  : 400
回复  : 3

[资源] web前端开发 php多进程初探

[复制链接]
htmlman的头像 楼主
本帖最后由 htmlman 于 2016-8-8 10:48 编辑

  准备

  我们都知道PHP是单进程执行的,PHP处理多并发主要是依赖服务器或PHP-FPM的多进程及它们进程的复用,但PHP实现多进程也意义重大,尤其是在后台Cli模式下处理大量数据或运行后台DEMON守护进程时,多进程的优势不用多说。

  PHP的多线程也曾被人提及,但进程内多线程资源共享和分配的问题难以解决。PHP也有多线程想关的扩展 pthreads ,但据说不太稳定,且要求环境为线程安全,所用不多。

  以前PHP群里的一位大神曾指导说后台PHP想进阶必然避不开多进程,正好公司里的守护进程也应用了PHP的多进程,结合着谷哥的各种资料和手册,总算理解了多进程,并自己写了一个小demo(在linux系统上实现的),用此文总结一下,如有错漏,谢谢提出。

  要实现PHP的多进程,我们需要两个扩展 pcntl和 posix,安装方法这里不再赘述。

  创建子进程

  创建PHP子进程是多进程的开始,我们需要 pcntl_fork() 函数;

  fork函数详解

  pcntl_fork() — 在当前进程当前位置产生分支(子进程)。此函数创建了一个新的子进程后,子进程会继承父进程当前的上下文,和父进程一样从pcntl_fork()函数处继续向下执行,只是获取到的pcntl_fork()的返回值不同,我们便能从判断返回值来区分父进程和子进程,分配父进程和子进程去做不同的逻辑处理。

  pcntl_fork()函数成功执行时会在父进程返回子进程的进程id(pid),因为系统的初始进程init进程的pid为1,后来产生进程的pid都会大于此进程,所以我们可以通过判断pcntl_fork()的返回值大于1来确实当前进程是父进程;

  而在子进程中,此函数的返回值会是固定值0,我们也可以通过判断pcntl_fork()的返回值为0来确定子进程;

  而pcntl_fork()函数在执行失败时,会在父进程返回-1,当然也不会有子进程产生。

  fork进程实例

  以下是fork子进程的一个简单的小例子:
  1. $ppid = posix_getpid();
  2.     $pid = pcntl_fork();
  3.     if ($pid == -1) {
  4.         throw new Exception('fork子进程失败!');
  5.     } elseif ($pid > 0) {
  6.         cli_set_process_title("我是父进程,我的进程id是{$ppid}.");
  7.      sleep(30); // 保持30秒,确保能被ps查到
  8.     } else {
  9.         $cpid = posix_getpid();
  10.         cli_set_process_title("我是{$ppid}的子进程,我的进程id是{$cpid}.");
  11.         sleep(30);
  12.     }
复制代码

  这时介绍一下两个函数:

  posix_getpid() :获取当前进程的pid;

  cli_set_process_title('响亮的名字') :为当前进程取一个响亮的名字。

  运行这个例子,我们便能看到当前两个PHP进程了。
2.png

  管理子进程

  创建好了进程,那么怎么对子进程进行管理呢?使用信号。

  在计算机科学中,信号是Unix、类Unix以及其他POSIX兼容的操作系统中进程间通讯的一种有限制的方式。它是一种异步的通知机制,用来提醒进程一个事件已经发生。

  分发信号处理器

  我们通过在父进程接收子进程传来的信号,判断子进程状态,来对子进程进行管理。

  我们需要在父进程里使用 pcntl_signal() 函数和 pcntl_signal_dispatch() 函数来给各个子进程安装信号处理器。
  1. pcntl_signal (int $signo , callback $handler) 安装一个信号处理器;
  2.         $signo是待处理的信号常量,callback是其处理函数

  3. pcntl_signal_dispatch () 调用每个等待信号通过pcntl_signal()安装的处理器
复制代码

  PHP内常见的信号常量有:
  1. SIGCHLD     子进程退出成为僵尸进程会向父进程发送此信号
  2.         SIGHUP      进程挂起
  3.         SIGTEM      进程终止
  4.         ...         // 其他请在手册中查看
复制代码

  安装并调用信号处理器后,一旦子进程有相应的信号返回给父进程,父进程就可以调用相应的callback函数对子进程处理;

  处理子进程

  对子进程的处理方法有:
  posix_kill() :此函数并不能顾名思义,它通过向子进程发送一个信号来操作子进程,在需要要时可以选择给子进程发送进程终止信号来终止子进程;

  pcntl_waitpid() :等待或返回fork的子进程状态,如果指定的子进程在此函数调用时已经退出(俗称僵尸进程),此函数将立刻返回,并释放子进程的所有系统资源,此进程可以避免子进程变成僵尸进程,造成系统资源浪费;

  下面是两个函数的函数原型:
  1. bool posix_kill ( int $pid , int $sig ) // 向进程id为$pid的进程发送$sig信号,$sig常见信号如上;

  2. int pcntl_waitpid ( int $pid , int &$status [, int $options = 0 ] )  // 挂起当前进程的执行直到进程号为$pid的进程退出(如果$pid为-1,则等待任意一个子进程);
复制代码

  总结

  这就是PHP多进程的基础使用了,感兴趣的可以自己写一个demo试一试手了。

  最后贴一下鸟哥所说的PHP多进程优点:

  使用多进程, 子进程结束以后, 内核会负责回收资源

  使用多进程,子进程异常退出不会导致整个进程Thread退出. 父进程还有机会重建流程.

  一个常驻主进程, 只负责任务分发, 逻辑更清楚.

  参考资料:

相关帖子

发表于 2016-8-9 13:26:56 | 显示全部楼层
PHP的多线程也曾被人提及,但进程内多线程资源共享和分配的问题难以解决。PHP也有多线程想关的扩展 pthreads ,但据说不太稳定,且要求环境为线程安全,所用不多。
使用道具 举报

回复

发表于 2016-8-10 20:38:48 | 显示全部楼层
经常看到”htmlman“发帖,辛苦了
使用道具 举报

回复

发表于 2016-8-12 15:35:09 来自手机 | 显示全部楼层
有空一起交流一下
使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部