layout: post
title: "PHP性能優(yōu)化初識"
date: 2016-05-04 22:46:21 +0800
comments: true
categories: [PHP]
PHP性能優(yōu)化
一、PHP性能優(yōu)化問題解析
PHP的性能問題,占整體項目性能問題的比例不足50%,所以在考慮性能優(yōu)化項目的時候,不要局限于僅優(yōu)化PHP。
PHP的性能優(yōu)化問題的解決方向(困難度從容易到簡單)
PHP語言級的性能優(yōu)化
PHP周邊問題的性能優(yōu)化(開發(fā)環(huán)境等)
PHP語言自身分析、優(yōu)化(底層C)
壓力測試工具簡介
Apache Benchmark(ab)
簡介
ab是由Apache提供的壓力測試軟件。安裝Apache服務(wù)器時會自帶該壓測軟件。
如何使用
./ab -n1000 -c100 http://www.baidu.com (目標(biāo)網(wǎng)址)
-n 請求數(shù)
-c 并發(fā)數(shù)
url 目標(biāo)壓測地址
結(jié)果分析
主要看
Request per second 每秒接受的請求數(shù)
Time per request 一個請求的耗時
二、PHP語言級的優(yōu)化
優(yōu)化點:少寫代碼,多用PHP自身能力,多使用PHP內(nèi)置的函數(shù),變量,常量
性能問題:自寫代碼冗余較多,可讀性不佳,并且性能低
為什么性能低?
我們自己寫的代碼每次需要編譯解析成底層語言,每一次請求都會處理一遍開銷很大。
PHP內(nèi)置函數(shù)的性能優(yōu)劣
情況描述:
PHP內(nèi)置函數(shù)之間依然存在著快慢差異
多去了解PHP內(nèi)置函數(shù)的時間復(fù)雜度
舉例
<?php
$start=current_time();
$i=0;
$arr=range(1,200000);
while($i<200000){
++$i;
//isset($arr[$i]); //測試結(jié)果50多ms
array_key_exists($i,$arr); //測試結(jié)果80多ms
}
$end=current_time();
echo "Lost Time:".number_format($end-$start,3)*1000;
echo "\n";
/**
*返回一個微秒級別的時間戳
*/
function current_time(){
list($usec,$sec)=explode("",microtime());
return ((float)$usce+(float)$sec);
}
?>
測試結(jié)果說明isset比array_key_exists函數(shù)更優(yōu)化。
減少PHP魔法函數(shù)的使用
情況描述:
PHP提供的魔法函數(shù)性能不佳
舉例
<?php
class test{
private $var="123";
public function __get($varname){
return $this->var;
}
}
$i=0;
while($i<10000-){
$i++;
$test=new test();
$test->var;
}//大概80ms
?>
<?php
class test{
public $var="123";
//public function __get($varname){
//return $this->var;
//}
}
$i=0;
while($i<100000){
$i++;
$test=new test();
$test->var;
}//大概50ms
?>
不使用魔法函數(shù),性能更優(yōu)化。
PS:
在Linux中可以使用 time php test.php
會輸出三個時間,主要關(guān)注user為執(zhí)行時間
產(chǎn)生額外開銷的錯誤抑制符@
情況描述:
@的實際邏輯是在代碼開始前結(jié)束后增加Opcode 忽略報錯。
在@這行前加入Opcode忽略報錯,又在這行結(jié)束后再加入Opcode,恢復(fù)報錯。
<?php
file_get_contents("XXX");
?>
用VLD擴(kuò)展看Opcode代碼:
php -dvld.active=1 -dvld.execute=0 at.php //我們只看代碼不執(zhí)行
有三行代碼
加上@符號后
有五行代碼
建議不要使用錯誤抑制符@,
多使用try catch
合理使用內(nèi)存
情況描述:
PHP有內(nèi)存回收機(jī)制保底,但也要小心使用內(nèi)存。
利用unset()及時釋放不適用的內(nèi)存(注:unset()出現(xiàn)注銷不掉的情況)
盡量少的使用正則表達(dá)式
情況描述:
正則表達(dá)式的回溯開銷較大。
避免在循環(huán)內(nèi)做運算
情況描述:
循環(huán)內(nèi)的計算式將會被重復(fù)計算
<?php
$str="Hello World!"
for($i=0;$i<strlen($str);$i++){//每次循環(huán)都會計算這個字符串的長度
//do something
}
?>
改進(jìn):
<?php
$str="Hello World!"
$strlen=strlen($str)
for($i=0;$i<$strlen;$i++){
//do something
}
?>
減少計算密集型業(yè)務(wù)
情況描述:
PHP的語言特性決定了PHP不適合密集型運算的場景。
因為PHP是基于C語言的,所以在處理大型運算的時候開銷是比C大很多的。
適合的場景:
銜接Webserver與后端服務(wù),UI呈現(xiàn)。
務(wù)必使用帶引號字符串做鍵值
情況描述:
PHP會將沒有引號的鍵值當(dāng)做常量,產(chǎn)生查找常量的開銷。
三、PHP周邊問題的性能優(yōu)化
Linux 運行環(huán)境
減少文件類的操作
常見PHP場景的開銷次序:
讀寫內(nèi)存<<讀寫數(shù)據(jù)庫(數(shù)據(jù)庫有內(nèi)存緩存)<讀寫磁盤<讀寫網(wǎng)絡(luò)數(shù)據(jù)(網(wǎng)絡(luò)延遲)
優(yōu)化網(wǎng)絡(luò)請求
可能的問題:
1. 對方接口的不確定因素
2. 網(wǎng)絡(luò)穩(wěn)定性
優(yōu)化:
1. 設(shè)置超時時間
連接超時(200ms)
讀超時(800ms)
寫超時(500ms)
2. 串行請求并行化
使用curl_multi_*() //取決于最長的連接時間所以不推薦
使用swoole擴(kuò)展
壓縮PHP接口輸出
使用Gzip壓縮即可
優(yōu)點:
利于我們的數(shù)據(jù)輸出,Client能更快獲取數(shù)據(jù)
缺點:
產(chǎn)生cpu額外開銷
可以考慮當(dāng)數(shù)據(jù)大于多少時再使用壓縮來優(yōu)化。
緩存重復(fù)計算的內(nèi)容
什么情況下:
多次請求,內(nèi)容不變 //使用模板渲染緩存 如smarty 開啟caching
重疊時間窗口思想和旁路方案
在幾個任務(wù)不強(qiáng)依賴前一個任務(wù)的輸出或者返回時??梢栽谏弦粋€任務(wù)沒完成時就執(zhí)行下一個任務(wù)
四、PHP性能分析
用XHPorf進(jìn)行PHP性能問題的具體分析
XHPorf:源自Facebook的PHP性能優(yōu)化工具
其他工具:
ab -壓力測試
vld -opcode 代碼分析
五、PHP性能瓶頸究極辦法
Opcode Cache : PHP擴(kuò)展APC,memcache
通過PHP擴(kuò)展代替原PHP代碼中高頻邏輯
Runtime優(yōu)化: HHVM