刚接触php的时候,就看到过php不支持多进程的,多线程,但是php可以利用其他的东西来实现伪多进程,多线程,例如:fsockopen实际是利用socket的多线程,popen,pcntl_fork,proc_open利用httpd多进程功能的外衣。下面就一些实践过程,以及这种多进程的效果,到底如何。
一,php利用socket来实现多线程
在服务器端有一个程序,与多个客户端程序通讯,其中主线程有一个socket绑定在一个固定端口上,负责监听客户端的 Socket信息。每当启动一个客户端程序,客户端发送来一个socket连接请求,server端就新开启一个线程,并在其中创建一个socket与该 客户端的socket通讯,直到客户端程序关闭,结束该线程。
<?php function thread($count=1) { for($i=0;$i<$count;$i++){ $fp=fsockopen($_SERVER['HTTP_HOST'],80); fputs($fp,"GET http://localhost/aaaa/getset.php\r\n"); fclose($fp); soc_log('socket',Date('d h:i:s', mktime()) . (double)microtime()); } } function soc_log($script,$start_time) { $fp = fopen($script.".log", 'a+'); fputs($fp, 'start time is ' . $start_time. "\n"); fclose($fp); } thread(5); for($j=0;$j<5;$j++){ soc_log('nosocket',Date('d h:i:s', mktime()) . (double)microtime()); } ?>
根据socket的这种特性,写了一小段代码,并且记录下每次连接socket的时间,以及不通过socket来,记录执行时间,我的本意是,如果php真的能实现多线程的话,socket.log和nosocket.log里面记录的时间是相同的。我用压力测试工具测试一下,这样做是为了尽量做到并发,这样log出现相同的时间可能性更大。
[zhangy@BlackGhost ~]$ /usr/local/bin/webbench -c 10 -t 5 http://localhost/aaaa/socket.php
我查看一下二个log文件里面根本没有相同的,感觉好像是错开的。后来我仔细想了想,访问socket.php这个页面时,里面还是通过php来执行程序,所以根本不可能向几个线程同时,发送请求,肯定有先,有后。
二,pcntl_fork利用httpd来实现多进程
开始的时候,我并不知道pcntl_fork是怎么利用什么来实现多进程的,无意中发现他是增加了httpd的进程数来实现多进程的。我汗。举例说明
<?php $pid = pcntl_fork(); echo "$pid<br>"; if ($pid == -1) { throw new Exception('could not fork'); } else if ($pid) { //we are the parent echo 'Forked successfully'; flush(); // posix_kill(posix_getpid(), SIGTERM); exit; } else { // posix_kill(posix_getpid(), SIGTERM); exit; } ?>
1,启动一下你的apache然后执行一下以下这个命令:
[root@BlackGhost pcntl]# ps -e|grep httpd |wc -l
10
也就是现在有10httpd进程
2,多执行一下上面的程序,然后在执行以下命令
[root@BlackGhost pcntl]# ps -e|grep httpd |wc -l
18
你会发现竟然多出来一些httpd进程,并且页面可以输出每个httpd的pid,如果不进行kill的话,随着请求的增加,httpd会不断的增加,直到死机为止。还有启动进程,和关闭进程,都要时间,这样频繁的开启,和关闭进程不见得能提高多少性能。还有pcntl只能用于php-cli,这就不用多说了,php-cgi里面根本没有httpd这个东西。如果你装apache的进修没有--enable-pcntl的话,可以用phpize来添加pcntl模块,请参考phpize增加php模块
其实也可以用top命令来看
[root@BlackGhost pcntl]# top top - 20:52:03 up 1:52, 1 user, load average: 0.08, 0.09, 0.07 Tasks: 122 total, 2 running, 120 sleeping, 0 stopped, 0 zombie Cpu(s): 10.6%us, 7.0%sy, 0.0%ni, 82.5%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 1027516k total, 889636k used, 137880k free, 139388k buffers Swap: 0k total, 0k used, 0k free, 257376k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 4468 zhangy 20 0 436m 225m 29m S 12 22.5 12:12.52 firefox-bin 4387 root 19 -1 59916 46m 12m S 5 4.7 3:19.78 X 8012 zhangy 20 0 53256 9040 2792 R 4 0.9 0:01.04 httpd 8030 zhangy 20 0 53256 8740 2492 S 4 0.9 0:01.90 httpd 8010 zhangy 20 0 53128 8772 2736 R 3 0.9 0:37.98 httpd 4541 zhangy 20 0 70540 29m 11m S 2 3.0 2:43.99 mplayer 4425 zhangy 20 0 56296 15m 9316 R 2 1.5 1:42.84 sakura 4399 zhangy 20 0 15680 9.9m 3032 S 1 1.0 1:27.18 python 4422 zhangy 20 0 46212 20m 12m S 0 2.1 0:38.40 python 8068 root 20 0 2348 1036 812 R 0 0.1 0:00.04 top 1 root 20 0 1704 616 552 S 0 0.1 0:00.81 init 2 root 20 0 0 0 0 S 0 0.0 0:00.00 kthreadd 3 root RT 0 0 0 0 S 0 0.0 0:00.00 migration/0 4 root 20 0 0 0 0 S 0 0.0 0:00.11 ksoftirqd/0
关于S这一列,下面有一些注释
R 正在运行,或在队列中的进程
S 处于休眠状态
T 停止或被追踪
Z 僵尸进程
W 进入内存交换(从内核2.6开始无效)
X 死掉的进程
< 高优先级
N 低优先级
L 有些页被锁进内存
s 包含子进程
+ 位于后台的进程组;
l 多线程,克隆线程
三,proc_open,popen也是利用httpd来实现多进程
<?php $proc=proc_open("echo foo", array( array("pipe","r"), array("pipe","w"), array("pipe","w") ), $pipes); print stream_get_contents($pipes[1]); ?>
检测方法可以和pcntl_fork一样,看一下httpd进程数的变化,popen和proc_open差不多就不多说了。
转载请注明
作者:海底苍鹰
地址:http://blog.51yip.com/php/992.html
你说的不对