php echo 前后有字符串,PHP echo长字符串的效率问题

偶然看到Volcano发表在http://www.ooso.net/archives/517/的博文,说PHP显示长字符串的时候会导致PHP执行时间超长问题。

正好前段时间研究过HTTP协议,想到可能与HTTP的Transfer-Encoding(数据传输模式)有关。

于是尝试重现Volcano遇到的问题。

(此时,apache没有开gzip压缩)

http://localhost/chunked.php:

$_start = microtime(true);

echo str_pad('___', 500*1024, "_"); //构造一个500KB的字符串

$_end = microtime(true);

$_time = $_end - $_start;

echo '
';

echo intval($_time*1000).'ms';

?>

用firefox打开,显示php平均执行时间在450ms左右。用firebug查看本次请求,显示数据是500KB,用时为700ms左右,传输模式(Transfer-Encoding)为chunked。

由于是本地,所以网速肯定比实际要快。于是我写了个脚本,来模拟网速慢的时候:

test.php:

get_lrc("http://localhost/chunked.php");

function get_lrc($url)

{

$url = parse_url($url);

if($fp = @fsockopen($url['host'],empty($url['port'])?80:$url['port'],$error))

{

fputs($fp,"GET ".(empty($url['path'])?'/':$url['path'])." HTTP/1.1\r\n");

fputs($fp,"Host:".$url['host']."\r\n");

fputs($fp,"Accept-Encoding: gzip,deflate\r\n\r\n");

while(!feof($fp))

{

echo fread($fp,1);

usleep(1); //每读取1个字节,暂停执行1微妙(1/1000毫秒)

}

fclose($fp);

}

else echo 'connect failed';

}

?>

这个程序在本地命令行模式下运行。显示php执行时间在24000ms左右。24秒啊!!!

然后打开apache 的gzip压缩。详细方法大家google一下,很多。

再次用firefox打开http://localhost/chunked.php,显示的php执行时间在12ms左右。用firebug查看,没有Transfer-Encoding: chunked。并且Content-Encoding: gzip。数据总量为545B。

再执行test.php,立即显示了一堆http头信息(其中也是没有chunked,有gzip),正文为乱码(因为gzip压缩过了)。人工估计运行时间也是非常短。

为什么会这样呢?

首先要说下chunked传输模式。

一般如果传输模式不是chunked,服务器返回的http头信息里面有一项为Content-Length,表示此次请求返回的正文内容长度。浏览器可以根据这个长度来取内容。

但是有的时候,需要在完全输出内容之前就要把内容传给浏览器,或者是刚开始不知道内容有多长。这个时候就要用到chunked模式。 在这个模式下面,http请求的正文会被切割成若干个段,每段开始有一个十六进制的数字表示本段的长度。长度数字和段落后面均以\r\n结尾。

对于php的输出,貌似apache采取的策略是小段输出直接传输,大段输出就切割成chunked分段。在chunked分段没有传输完成之前,apache和php一直保持连接状态。

也就是说,如果php的输出字符串比较小,那么apache会把这些数据暂存,等到php执行完了之后再发给浏览器。而当php输出大段字符的时候,apache就不会缓存输出,直接把输出丢给浏览器,而且在此过程中会暂时停止php的执行!

这种情况看起来是挺吓人的,网速居然影响了php的效率! 但是仔细想想,php只是暂停执行而已,可能和sleep的效果差不多。不过由此带来的性能影响我还没测试过。 要想避免这种情况很好办,只需要强制apache每次都缓存php的输出即可(具体设置我还没发现,不过如果开启apache的gzip压缩,肯定是以强制缓存输出为必要条件的。)。

当然,这只是我根据测试结果的一些推测,如果有不妥的地方,请大家指出。

7421 read 18 comment(s)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值