php 多进程实用小结

来源:互联网 发布:mac照片导入iphone 编辑:程序博客网 时间:2024/05/21 18:36

前提:众所周知,php都是单进程处理的,处理多并发呢主要是依赖php-fpm多进程,以及他们进程的复用。但是我们使用php多进程也是很有意义的,特别是在cli模式下处理大数据,或者运行后台DEMON守护进程时,多进程的优势不用多说。
主要用到pcntl的扩展以及相关方法函数。
我为什么用到了多进程
公司项目中,有一个业务类似定时任务去第三方拉取数据,然后修改自己的业务。一般这种需求第一首先想到的就是crontab,直接走定时任务。没错,最开始我也是这样想的,但是我后来想了一下,定时任务定多长时间执行一次呢,短了的话 可能会造成数据重复处理,虽然有补救错误不影响业务,但是处理重复数据是没有任何意义的。所以最初我的想法是后台nohup守护进程,然后代码里面是无限递归的方式,这样的话可以避免数据重复处理,也能实现实时性。但是紧接着另外一个问题出来了。因为代码里面是无限递归的方式,你声明的变量加上从第三方拉取的数据都会占用内存,随着时间的推移,你的代码占用的内存会越来越大,最终超过了ini中的阀值,就会杀死进程,php在回收内存方面比较薄弱。我最开始也看了鸟哥的博客,谁动了我的内存那篇文章,了解了php内存是怎么回事。事实也能证明,你及时的unset掉变量,内存也会回收。但是代码何其长,变量何其多,这样的话 在代码中要加很多的unset,不但代码不美观,质量也下降了很多,无奈之举我接触到了php多进程。
我是怎么用php多进程来处理这个业务的
首先我们要对php多进程的概念熟悉一下
创建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,当然也不会有子进程产生。
我们创建了子进程去处理数据业务,我们还得知道什么时候子进程结束,然后创建下一个子进程继续处理。这里我们会用到另外一个函数pcntl_waitpid();
pcntl_waitpid函数详解:
挂起当前进程的执行直到参数pid指定的进程号的进程退出, 或接收到一个信号要求中断当前进程或调用一个信号处理函数。

如果pid指定的子进程在此函数调用时已经退出(俗称僵尸进程),此函数 将立刻返回
返回值:
pcntl_waitpid()返回退出的子进程进程号,发生错误时返回-1,如果提供了 WNOHANG作为option(wait3可用的系统)并且没有可用子进程时返回0。
我们可以根据返回值来判断子进程是否出来完毕,然后继续创建进程来处理。
说了这么多 贴下我自己的代码demo
多进程demo
使用这种方法处理大数据很适用,类似mapreduce。当然了我这种是一个子进程完了之后才会创建另外一个进程。如果大家要一下子创建多个子进程的话,需要对子进程管理就会用到信号的概念,稍微复杂,有兴趣的可以google。