基准测试技术
1.PHP应用程序栈
2.定义请求/响应生命周期
如图,一个简单的用户HTTP请求,它想Web服务器请求获取内容,依次经过用户的主路由器(如果有的话)、ISP网关和域名服务器(DNS),并且在DNS中会查找与请求的域名相关联的IP,然后到达具有指定IP的Web服务器,并最终请求Web程序生成特点内容
一旦到达Web服务器之后,通过获取并格式化用户请求数据来准备响应,然后Web服务器就会将数据打包成多个数据包,并以相反的顺序沿着用户请求的相同路径将这些数据包发送给用户。如果数据足够大,则采用多个数据包发送。检查在传输期间是否有错误并由浏览器重建,然后浏览器便开始其呈现过程
3.ab测试
响应信息:
其中HTML transferred、Requests per second以及Time per request可以让我们大致了解Web服务器为一个请求返回的数据量、Web服务器一秒可以处理的请求总数以及一个请求成功地收到来自Web服务器的响应所花费的总时间
ab选项:
-c 模拟并发请求数
-n 要执行的总数
-t 执行模拟所需要的时间
ab -n 100 -c 10 -t 20 url
Web服务器设置:在启用keep-Alive设置,Web服务器可以打开特定数量的连接,然后服务器可以保持这些连接处于打开状态以满足其他传入的请求。这样不再需要Web服务器为每个传入请求打开一个连接,满足请求后再关闭这个连接
提高客户端下载和呈现内容
1>使用工具(Firebug、YSlow、Page Speed)获取一下信息:
Web服务器发送的响应的细节信息
分析js逻辑
浏览器将读取的资源的逐项列表
浏览器获取和接受资源所花费的时间
对如何优化响应的建议
第二个工具集 (YUI Compressor、Closure Compiler和Smush.it)将帮助我们优化响应,我们可以用这些工具压缩js、css以及图像
2>其中YSlow会检查服务器响应头中的几个元素,会判断服务器是否采用Gzip/bzip2压缩,DNS查找是否有所减少,是否实现了Etag,Smush.it可以进一步减少图像文件的大小,Closure Compiler通过减少向Web服务器请求的数量可以减少浏览器必须通过internet获取资源的次数,在处理js的时候可以将所需要的js合并成一个文件从而轻松实现减少资源请求的目的
PHP代码优化
1.PHP最佳实践
1>使用逗号连接字符串
echo 'hi','there';
原因:echo1使用,相连 echo2 使用.相连
图一 echo1
图二 echo2
2>require与require_once
由于在导入PHP脚本时将进行大量的操作状态(stat)调用,因此require要快于require_once,如果你请求的文件位于多级目录下,则操作系统在到达所执行php文件之前每个目录中进行stat调用,require也会调用stat调用,但是次数较少。较少的函数调用,代码运行也会更快
注:在鸟哥的博客有提过,缺点其一:require_once需要查询一遍已加载的文件列表,确认是否存在,然后加载,其二,php判断一个文件是否加载,是需要得到这个文件的opend_path,他并不知道这个文件的实际路径是什么, 也就无法从已加载的文件列表去判断是否已经加载, 所以在include_once的实现中, 会首先尝试解析这个文件的真实路径(对于普通文件这个解析仅仅类似是检查getcwd和文件路径, 所以如果是相对路径, 一般是不会成功), 如果解析成功, 则查找EG(include_files)
过程是:
1. 尝试解析文件的绝对路径, 如果能解析成功, 则检查EG(included_files), 存在则返回, 不存在继续
2. 打开文件, 得到文件的打开路径(opened path)
3. 拿opened path去EG(included_files)查找, 是否存在, 如果存在则返回, 不存在继续
4. 编译文件(compile_file)
APC劫持了compile_file这个编译文件的指针,会有一些未定义的问题,
地址:http://www.laruence.com/2012/09/12/2765.html
3>提前计算数组长度,避免在for循环中 count($items)
4>使用foreach循环代替while或for循环
for:循环数字数组时,for需要事先count($arr)计算数组长度,需要引入自增变量$i,每次循环都要进行条件判断$i<$c,然后自增$i++,输出数组元素时,$arr[$i]需要进行哈希操作
foreach:循环数组时,指针会自动指向下一个元素,不需要计算数组长度,没有条件判断和自增变量,调用元素时也没有哈希操作,所以性能肯定要比for和while高.另外,for和while对存在键值映射的关联数组无能为力
foreach 和wihile比较:
一般情况下,会认为while应该比foreach快,因为foreach开始执行的时候首先把数组复制进去,而while直接移动内部指针,但是实际是这样:
在循环里进行的是数组“读”操作,则foreach比while快:
foreach ($array as $value) {
echo $value;
}
while (list($key) = each($array)) {
echo $array[$key];
}
在循环里进行的是数组“写”操作,则while比foreach快:
foreach ($array as $key => $value) {
echo $array[$key] = $value . '...';
}
while (list($key) = each($array)) {
$array[$key] = $array[$key] . '...';
}
总结:实际情况上,如果仅仅是在循环进行数组的读操作,那么foreach是很快,这是因为php采用的复制机制是“引入计数,写时复制”,之所以这么做是处于节约内存消耗的目的,同时也提高了复制效率,经过反复多次测试,结果表明,对于遍历同样一个数组,foreach速度最快,最慢的则是while。一般逻辑下认为,while应该比foreach快(因为foreach在开始执行的时候首先把数组复制进去,而while直接移动内部指标。),但结果刚刚相反。原由应该是,foreach是PHP内部实现,而while是通用的循环结构。
5>文件访问
四种读取数据的方法: fread()、file_get_contents()、file()和readfile()
file_get_contents和fread()以字符串形式返回数据,而file()则将文件中的数据作为数组返回
只有file_get_contents将文件缓存在内存中,以便更快地进行读写操作,这种方式称为内存映射
在读取小文件的时候fread()比file_get_contents快一些
opcode缓存
1.PHP的生命周期
每次对脚本发出请求时,它必须执行途中的所有步骤,每次在针对特定PHP脚本的请求到达时,即使该PHP脚本的内容没有任何变化,Zend引擎也会重新创建该文件的opcode。对弈脚本的初次请求这些是必要的,但后续请求则无需如此操作,如果实现opcode缓存,我们就可以省略 词典扫描、解析、创建opcode这些步骤从而提高应用程序的性能
第二条路径从请求.php文件开始,然后检查共享内存,确定opcode是否已被成功缓存,由于出事请求创建的opecode并将其存储在缓存中,所以zend引擎可以从缓存中获取opcode并使用它
具体的在php与mysql高性能应用开发读后感里面有详细说明