由于工作需要,今天研究了下php的多进程和多线程,今天先说一下多进程吧。主要说一样,多进程和多线程的区别;为什么他们都只能运行在php的cli模式下;以及多进程到底父进程和子进程是怎么工作的,什么顺序(先运行哪个进程)。结合我操作的实例简单总结一下,因为自己接触这方面也比较短,有什么错误或不足希望大家指正。
首先说一下为什么php要使用他们,很多phper可能一般都用不到这些,这取决于php本身作为web脚本的特性,他是阻断的、高并发的。所以有的人都认为php没有多进程和多线程,其实语言本地没有这样的区分,语言都是寄生在系统上的,系统支持,那么php做个扩展,就可以支持了啊。只是这些功能大家会不会用到而已,没有能不能之说。在一些特殊条件下,比如安全或完整性要求不是很高的采集,以及php做守护进程分发任务时用他们是比较好的。采集用多线程,汇总线程结果要比较for循环等快好几倍,守护进程用多进程,可以防止php直接做守护进程带来的内存溢出被kill掉。因为父进程可以只做分发,由子进程去做任务,这样子进程死了,也不会影响父进程。
2、多进程和多线程的区别。
我们应该知道php版本分一个nts和ts版本。即非线程安全和线程安全。这个其实比较好理解,大家可以查一下有很多资料。大家可以查一下php的几种运行模式的区别,对这方便理解有一定帮助。熟悉linux的应该比较容易理解进程的概念,很多php扩展也是考虑在linux多进程模式下编译开发的。所以php最好还是运行在linux比较好。多进程和多线程的作用都是一样的,都是类似与并行(当然不可能是真正的并行,可以说是快速轮询)来做一件或多件事情。这样会大大缩小程序执行的时间,多进程要更加消耗系统资源,但是更加安全稳定,因为某个子进程甚至父进程死掉,都不会影响其他进程,父进程先死掉,子进程会归属到1的父进程,运行完回收,子进程先死掉就更没问题了。而多线程更节省系统资源,但是一个线程崩溃,整个进程就挂掉。所以php这种等待返回,要根据程序执行结果操作的一般做法,可能不理解为什么要用这样不能保证安全的东西。这些东西当然是有他们的作用的。
3、为什么只能运行在cli模式下
这里我测试的是fpm-fcgi模式和cli模式,fpm-fcgi是一种常驻进程,并且可以请求复用此进程的模式。那么可想而知,如果子进程还在运行,但父进程请求结束处理新请求,就会乱了,而cli模式,php是以守护进程的方式运行,相当于一个请求一个守护进程,这样才能保证其对应关系。我是这样理解的。
4、使用
pcntl的扩展的安装就不说了,很简单,这里结合实例说一下pcntl_fork的运行方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?php echo $pid= pcntl_fork(); if ($pid == -1) { die('could not fork'); } else if (!$pid) { //这里是子进程 echo '-'; exit(); }else{ //这里是父进程 echo 'A'; echo 'B'; } |
我用cli运行多次的结果是
$pid为0说明是子进程,因为pcntl_fork()的作用就是当程序运行到这里,就试图去创建一个子进程,如果创建成果,那么返回当前进程的子进程id,0表示当前进程没有子进程,那么其进程本身不就是子进程了,而如果有进程id,表示其有子进程,那么其不就是父进程。就好像是从这个位置其,下面的所有代码被复制到了另一个进程中执行一样,产生了一个子进程。但是从上面多次执行结果看,大部分情况下是先执行子进程的,这和我之前网上查的资料有些出入,而且这个顺序也不是固定的。但是我们发现倒数第三条,是先执行父进程,后执行的子进程,这时候子进程是有一定风险的,虽然子进程不会死,因为他会过继到1进程,但如果要等待子进程执行完可以这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?php echo $pid= pcntl_fork(); if ($pid == -1) { die('could not fork'); } else if (!$pid) { //这里是子进程 echo '-'; exit(); }else{ //这里是父进程 echo 'A'; pcntl_wait($status);//父进程执行到这里等等子进程执行完再执行 echo 'B'; } |
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
0-31843AB[root@client 60.test.com]# php index.php 0-31845AB[root@client 60.test.com]# php index.php 0-31847AB[root@client 60.test.com]# php index.php 0-31849AB[root@client 60.test.com]# php index.php 0-31851AB[root@client 60.test.com]# php index.php 0-31853AB[root@client 60.test.com]# php index.php 0-31855AB[root@client 60.test.com]# php index.php 31857A0-B[root@client 60.test.com]# php index.php 0-31859AB[root@client 60.test.com]# php index.php 0-31861AB[root@client 60.test.com]# php index.php 0-31863AB[root@client 60.test.com]# php index.php 0-31865AB[root@client 60.test.com]# php index.php 0-31867AB[root@client 60.test.com]# php index.php 0-31869AB[root@client 60.test.com]# php index.php 0-31871AB[root@client 60.test.com]# php index.php 0-31873AB[root@client 60.test.com]# php index.php 0-31875AB[root@client 60.test.com]# php index.php 0-31877AB[root@client 60.test.com]# php index.php 0-31879AB[root@client 60.test.com]# php index.php 0-31881AB[root@client 60.test.com]# php index.php 0-31883AB[root@client 60.test.com]# php index.php |
我们发现,当然大部分是先执行了子进程,当然我认为可能是因为我写的子进程的操作太过简单,所以先输出了子进程的执行结果页不一定,但是这一条
1 |
31857A0-B[root@client 60.test.com]# php index.php |
就是我们想要的结果了,其他都没有问题,因为都是先执行的子进程,而这条是先执行了父进程,走到输出A就等子进程执行完才执行的下面的。所以这就是
1 |
pcntl_wait($status) |
的作用。
好了,基本就是这些了。至于进程间或线程间的通信,可以利用类似共享内存变量等的来做。具体情况具体对待吧。
程序本天成,妙手偶得之!我们只是代码的搬运工!
转载请注明:http://www.521php.com/archives/1708/
2015年02月10日 上午 9:41 技术笔记大全 | 引用 | #1
正在研究多线程和多进程,博主写的不错,顶一下