php真的有多进程,多线程吗?

张映 发表于 2010-08-31

分类目录: php

标签:, , , , , ,

刚接触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/comment-page-1

1 条评论

  1. qq 留言

    你说的不对