查看完整版本: PHP應用程式之性能優化
頁: [1]

鼎皓 發表於 2007-12-23 03:02 PM

PHP應用程式之性能優化

使用PHP編程的最大好處是學習這種編程語言非常容易以及其豐富的庫。即使對需要使用的函數不是十分瞭解,我們也能夠猜測出如何完成一個特定的任務。

儘管PHP非常簡單易學,但我們仍然需要花費一點時間來學習PHP的一些編程技巧,尤其是與性能和記憶體佔用相關的技巧。在PHP中,有許多小技巧能夠使我們減少記憶體的佔用,並提高應用程式的性能。在本篇文章中,我們將對PHP應用程式的分析、如何改變腳本代碼以及比較優化前後的各種參數值進行簡要的介紹。

通過在程式中設置計時的程式,並反復執行這些代碼,我們可以獲得有關程式執行速度的一組資料,這些資料可以可以用來發現程式中的瓶頸,以及如何進行優化,提高應用程式的性能。

也許讀者曾經聽說過PEAR庫吧。我們將使用PEAR庫創建在分析時需要使用的例子,這也是對現有的代碼進行分析的最簡單的方法,它使我們無需使用商用產品就能對代碼進行分析。

我們要使用的庫的名字是PEAR::Benchmark,它對於對代碼進行分析和性能測試非常有用。這個庫提供一個名字為Benchmark_Timer()的類,能夠記錄一個函數調用和下一個函數調用之間的時間。在對代碼的性能進行測試時,我們可以得到一個詳細的腳本執行結果,它非常簡單,如下所示:

<?php

include_once("Benchmark/Timer.php");

  $bench = new Benchmark_Timer; $bench->start();

  $bench->setMarker('Start of the script'); 現在處於睡眠狀態幾分鐘

  sleep(5); $bench->stop(); // 從計時器中獲得分析資訊

  print_r($bench->getProfiling());

?>

上面代碼執行後的輸出如下所示:



Array

  (

   => Array

  (

   => Start

   => 1013214253.05751200

   => -

   => 0

  )

=> Array

  (

   => Start of the script

   => 1013214253.05761100

   => 9.8943710327148E-05

   => 9.8943710327148E-05

  )

=> Array

  (

   => Stop

   => 1013214258.04920700

   => 4.9915959835052

   => 4.9916949272156

  )

  )

上面的數位似乎是一組雜亂無章的數位,但如果程式的規模更大,這些數位就十分地有用了。

也許廣大讀者也能猜測到,陣列的第一個表目是實際調用Benchmark_Timer()類的方法,例如

$bench->start()、$bench->setMarker()和$bench->stop(),與這些表目有關的數字是相當簡單的,現在我們來仔細地研究這些數字:

=> Array

  (

   => Start

   => 1013214253.05751200

   => -

   => 0

  )

time表目指的是何時對Benchmark_Timer()的start()方法調用的UNIX的timestamp,diff表目表示這次調用和上次調用之間的時間間隔,由於這裏沒有上一次,因此顯示出了一個破折號,total表目指的是自測試開始到這一特定的調用之前代碼運行的總的時間。下面我們來看看下一個陣列的輸出:

=> Array

  (

   => Start of the script

   => 1013214253.05761100

   => 9.8943710327148E-05

   => 9.8943710327148E-05

  )

從上面的數字我們可以看出,在調用$bench->start()之後,程式運行了9.8943710327148E-05秒(也就是

0.0000989秒)後開始調用$bench->setMarker(....)。

一次真實的性能測試經歷

儘管上面的例子不錯,但在對於決定如何優化你的站點代碼設計方面,它真的不能算是一個好例子。下面我將用我自己作為網站技術人員的一段親身經歷來說明如何解決性能方面存在的問題。

我並不大理解網站使用的代碼,因為它是根據特殊的需求,歷經多年開發而成的━━其中的一個模組包括網站轉換代碼,另一個模組記錄網站的使用情況,其他的模組也各有各的作用。我和網站的主要開發者都意識到網站的代碼需要優化,但又不清楚問題出在哪兒。

為了儘快地完成任務,我開始研究網站的主要腳本代碼,並在全部腳本代碼以及其包含檔中添加了一些$bench->setMarker()命令,然後分析$bench->getProfiling()的輸出,並對得到的結果大吃一驚,原來問題出在一個與獲得特定語言名字(例如en代表english)的轉換代碼的函數調用中,該函數在每個頁面上都會被使用數百次。每次調用該函數時,腳本代碼都會對一個MySQL資料庫進行查詢,從一個資料庫表中獲得真正的語言名字。

於是我們這一類的資訊創建了一個緩衝系統。經過短短2天時間的工作,我們使系統的性能得到了很大的提高,第一周內頁面的流覽量也因此而增加了40%。當然了,這只是一個有關分析代碼能夠提高互聯網應用或互聯網網站性能的例子。

性能測試函數調用



在分析一個腳本或網頁(以及其包含檔)時,儘管Benchmark_Timer()特別有用,但它並不科學,因為要獲得分析的資料我們必須多次載入腳本,而且它也不是針對某個類或函數調用的。

PEAR::Benchmark庫中的另一個被稱作Benchmark_Iterator的類能夠很好地解決這一個問題,它能夠針對特定的函數或類的方法,顯示其分析資訊。它的用途是能夠能夠從測試中獲得一致的結果,因為我們知道,如果運行一段腳本一次,其運行時間為10秒,並不意味著它每次的運行時間總是10秒。

In any case, let's see some examples:

// 連接資料庫的代碼

  include_once("DB.php");

  $dsn = array(

  'phptype' => 'mysql',

  'hostspec' => 'localhost',

  'database' => 'database_name',

  'username' => 'user_name',

  'password' => 'password'

  );

  $dbh = DB::connect($dsn); function getCreatedDate($id)

  {

  global $dbh; >$stmt = "SELECT created_date FROM users WHERE id=$id";

  // 在這裏使用PEAR::DB

  $created_date = $dbh->getOne($stmt);

  if ((PEAR::isError($created_date)) ||

  (empty($created_date))) {

  return false;

  } else {

  return $created_date;

  }

  }include_once 'Benchmark/Iterate.php';

  $bench = new Benchmark_Iterate; // 運行getDate函數10次

  $bench->run(10, 'getCreatedDate', 1);// 列印分析資訊

  print_r($bench->get());

  ?>


運行上面的代碼能夠產生與下面相似的結果:

Array

  (

   => 0.055413007736206

   => 0.0012860298156738

   => 0.0010279417037964

   => 0.00093603134155273

   => 0.00094103813171387

   => 0.00092899799346924

   => 0.0010659694671631

   => 0.00096404552459717

   => 0.0010690689086914

   => 0.00093603134155273

   => 0.0064568161964417

   => 10

  )

上面的這些數字很好理解,mean條目表示getCreatedDate()函數10次運行的平均時間。在進行實際測試時,應該至少運行1000次,但這個例子得出的結果已經足夠說明問題了。

結束語:

希望廣大讀者能夠通過本篇文章掌握如何迅速地對PHP代碼進行分析的基本方法。在這裏我還還要提醒廣大讀者的是,對代碼進行分析不是一件簡單的事兒,因為我們必須掌握大量的有關該種語言的特性。在代碼中添加計時用的代碼有助於找出運行速度緩慢的函數,利用多次重複的方法使我們能夠發現對代碼進行正確優化的方法。...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div><div></div>

lunar3 發表於 2007-12-25 12:10 PM

嗯,你說的對,但是通常沒時間優化代碼:05:

kancu 發表於 2010-2-4 03:15 AM

不錯的分析,這也一直是程式設計努力的目標─如何讓程式執行的更快,但是通常是運作正常且速度不會太誇張就不會去管他了。

gemini21 發表於 2010-2-8 05:15 AM

回復 1# 鼎皓

原來PEAR也有這種分析工具 ....

teshuva 發表於 2010-5-27 03:21 AM

哎~~該怎麼說呢?
優化代碼是一個看得到摸不到的事 -- 就是沒有時間優化它咩
在學校寫的時候,就沒有時間優化了
更別說出社會了…
或許以後有機會當老師時,可能可以把這個觀念教下去吧…
感謝大大的分享喔^^<br><br><br><br><br><div></div>

eyefoto 發表於 2014-7-31 11:49 AM

感謝分享,超級受用!

daniel620406 發表於 2018-12-29 11:58 AM

這麼厲害的嗎?
值得測試跟了解一下

ckl94606 發表於 2019-4-10 01:19 AM

感謝大大的分享,又學習都新的資源。
頁: [1]