การเพิ่มประสิทธิภาพการทำงานของแอปพลิเคชัน PHP
ประโยชน์ที่ใหญ่ที่สุดของการเขียนโปรแกรมใน PHP คือความง่ายในการเรียนรู้ภาษาการเขียนโปรแกรมนี้และไลบรารี่ที่หลากหลาย แม้ว่าเราจะไม่รู้มากนักเกี่ยวกับฟังก์ชันที่ต้องใช้ แต่เราก็เดาได้ว่าจะทำงานเฉพาะเจาะจงให้สำเร็จได้อย่างไร
แม้ว่า PHP จะง่ายและเรียนรู้ได้ง่าย แต่เรายังคงต้องใช้เวลาเล็กน้อยในการเรียนรู้ทักษะการเขียนโปรแกรมบางอย่างของ PHP โดยเฉพาะทักษะที่เกี่ยวข้องกับประสิทธิภาพและการใช้หน่วยความจำ ใน PHP มีเคล็ดลับมากมายที่ช่วยให้เราสามารถลดการใช้หน่วยความจำและปรับปรุงประสิทธิภาพของแอปพลิเคชันได้ ในบทความนี้ เราจะแนะนำการวิเคราะห์แอปพลิเคชัน PHP สั้นๆ วิธีเปลี่ยนโค้ดสคริปต์ และเปรียบเทียบค่าพารามิเตอร์ต่างๆ ก่อนและหลังการปรับให้เหมาะสม
ด้วยการตั้งค่าขั้นตอนเวลาในโปรแกรมและดำเนินการโค้ดเหล่านี้ซ้ำ ๆ เราจะได้รับชุดข้อมูลเกี่ยวกับความเร็วในการดำเนินการของโปรแกรม ข้อมูลนี้สามารถใช้เพื่อค้นหาปัญหาคอขวดในโปรแกรมและวิธีเพิ่มประสิทธิภาพเพื่อปรับปรุงประสิทธิภาพของโปรแกรม แอปพลิเคชัน.
บางทีผู้อ่านอาจเคยได้ยินเกี่ยวกับห้องสมุด PEAR เราจะใช้ไลบรารี PEAR เพื่อสร้างตัวอย่างที่เราจำเป็นต้องใช้ระหว่างการวิเคราะห์ นี่เป็นวิธีที่ง่ายที่สุดในการวิเคราะห์โค้ดที่มีอยู่ ซึ่งช่วยให้เราวิเคราะห์โค้ดได้โดยไม่ต้องใช้ผลิตภัณฑ์เชิงพาณิชย์
ชื่อของไลบรารีที่เราจะใช้คือ PEAR::Benchmark และมีประโยชน์มากสำหรับการจัดทำโปรไฟล์และการทดสอบโค้ด ไลบรารีนี้มีคลาสชื่อ Benchmark_Timer() ซึ่งสามารถบันทึกเวลาระหว่างการเรียกใช้ฟังก์ชันหนึ่งและการเรียกใช้ฟังก์ชันครั้งถัดไป เมื่อทดสอบประสิทธิภาพของโค้ด เราจะได้ผลลัพธ์การดำเนินการสคริปต์โดยละเอียด ซึ่งง่ายมาก ดังนี้
include_once("เกณฑ์มาตรฐาน/Timer.php");
$bench = Benchmark_Timer ใหม่;
$ม้านั่ง->เริ่มต้น();
$bench-> setMarker('เริ่มสคริปต์');
// ขณะนี้อยู่ในสถานะสลีปไม่กี่นาที
นอน(5);
$ม้านั่ง->หยุด();
// รับข้อมูลการวิเคราะห์จากตัวจับเวลา
print_r($bench->getProfiling());
-
ผลลัพธ์หลังจากรันโค้ดข้างต้นจะเป็นดังนี้:
อาร์เรย์
-
[0] => อาร์เรย์
-
[ชื่อ] => เริ่มต้น
[เวลา] => 1013214253.05751200
[ความแตกต่าง] => -
[ทั้งหมด] => 0
-
[1] => อาร์เรย์
-
[name] => จุดเริ่มต้นของสคริปต์
[เวลา] => 1013214253.05761100
[ความแตกต่าง] => 9.8943710327148E-05
[ทั้งหมด] => 9.8943710327148E-05
-
[2] => อาร์เรย์
-
[ชื่อ] => หยุด
[เวลา] => 1013214258.04920700
[ความแตกต่าง] => 4.9915959835052
[ทั้งหมด] => 4.9916949272156
-
-
ตัวเลขด้านบนอาจดูเหมือนเป็นชุดตัวเลขที่ไม่ต่อเนื่องกัน แต่หากขนาดของโปรแกรมใหญ่กว่านี้ ตัวเลขเหล่านี้จะมีประโยชน์มาก
บางทีผู้อ่านส่วนใหญ่ยังสามารถเดาได้ว่ารายการแรกในอาร์เรย์เป็นวิธีการจริงในการเรียกคลาส Benchmark_Timer() เป็นต้น
$bench->start(), $bench->setMarker() และ $bench->stop() ตัวเลขที่เกี่ยวข้องกับรายการเหล่านี้ค่อนข้างง่าย
[0] => อาร์เรย์
-
[ชื่อ] => เริ่มต้น
[เวลา] => 1013214253.05751200
[ความแตกต่าง] => -
[ทั้งหมด] => 0
-
รายการเวลาอ้างอิงถึงการประทับเวลา UNIX เมื่อเรียกใช้เมธอด start() ของ Benchmark_Timer() รายการต่างระบุช่วงเวลาระหว่างการโทรนี้และการโทรครั้งสุดท้าย เนื่องจากไม่มีการเรียกก่อนหน้านี้ ที่นี่จึงเป็น Dash ซึ่งเป็นรายการทั้งหมด หมายถึงเวลาทั้งหมดที่โค้ดทำงานตั้งแต่เริ่มการทดสอบจนถึงการโทรครั้งนี้ ลองดูที่ผลลัพธ์ของอาร์เรย์ถัดไป:
[1] => อาร์เรย์
-
[name] => จุดเริ่มต้นของสคริปต์
[เวลา] => 1013214253.05761100
[ความแตกต่าง] => 9.8943710327148E-05
[ทั้งหมด] => 9.8943710327148E-05
-
จากตัวเลขข้างต้น เราจะเห็นได้ว่าหลังจากเรียก $bench->start() โปรแกรมจะทำงานเป็นเวลา 9.8943710327148E-05 วินาที (นั่นคือ 0.0000989 วินาที) ก่อนที่จะเรียก $bench->setMarker(….)
ประสบการณ์การทดสอบประสิทธิภาพที่แท้จริง
แม้ว่าตัวอย่างข้างต้นจะดี แต่ก็ไม่ใช่ตัวอย่างที่ดีสำหรับการตัดสินใจว่าจะเพิ่มประสิทธิภาพการออกแบบโค้ดของไซต์ของคุณอย่างไร ด้านล่างนี้ ฉันจะใช้ประสบการณ์ส่วนตัวของตัวเองในฐานะช่างเทคนิคเว็บไซต์เพื่อแสดงวิธีแก้ปัญหาด้านประสิทธิภาพ
ฉันไม่เข้าใจโค้ดที่เว็บไซต์ใช้จริงๆ เนื่องจากได้รับการพัฒนามาเป็นเวลาหลายปีตามความต้องการเฉพาะ - โมดูลหนึ่งประกอบด้วยโค้ดการแปลงเว็บไซต์ อีกโมดูลหนึ่งบันทึกการใช้งานของเว็บไซต์ และโมดูลอื่นๆ มีรหัสของตัวเอง บทบาทของแต่ละคน นักพัฒนาหลักของเว็บไซต์และฉันต่างตระหนักดีว่าโค้ดของเว็บไซต์จำเป็นต้องได้รับการปรับให้เหมาะสม แต่เราไม่รู้ว่าปัญหาคืออะไร
เพื่อให้งานเสร็จเร็วที่สุดเท่าที่จะเป็นไปได้ ฉันเริ่มศึกษาโค้ดสคริปต์หลักของเว็บไซต์ และเพิ่มคำสั่ง $bench->setMarker() ลงในโค้ดสคริปต์ทั้งหมดและไฟล์ที่รวมอยู่ จากนั้นจึงวิเคราะห์ผลลัพธ์ของ $bench ->getProfiling() และฉันรู้สึกประหลาดใจกับผลลัพธ์ ปรากฎว่าปัญหาเกิดขึ้นในการเรียกใช้ฟังก์ชันที่เกี่ยวข้องกับโค้ดการแปลงเพื่อรับชื่อภาษาเฉพาะ (เช่น en สำหรับภาษาอังกฤษ) ซึ่งถูกใช้หลายร้อยครั้ง ในแต่ละหน้า ทุกครั้งที่เรียกใช้ฟังก์ชันนี้ โค้ดสคริปต์จะสอบถามฐานข้อมูล MySQL เพื่อรับชื่อภาษาจริงจากตารางฐานข้อมูล
ดังนั้นเราจึงสร้างระบบบัฟเฟอร์สำหรับข้อมูลประเภทนี้ หลังจากทำงานเพียง 2 วัน เราได้ปรับปรุงประสิทธิภาพของระบบอย่างมาก และจำนวนการดูหน้าเว็บเพิ่มขึ้น 40% ในสัปดาห์แรก แน่นอนว่านี่เป็นเพียงตัวอย่างหนึ่งของการวิเคราะห์โค้ดที่สามารถปรับปรุงประสิทธิภาพของแอปพลิเคชันอินเทอร์เน็ตหรือเว็บไซต์อินเทอร์เน็ตได้อย่างไร
การเรียกใช้ฟังก์ชันทดสอบประสิทธิภาพ
แม้ว่า Benchmark_Timer() จะมีประโยชน์อย่างยิ่งเมื่อวิเคราะห์สคริปต์หรือเว็บเพจ (และไฟล์ที่มีสคริปต์อยู่) แต่ก็ไม่เป็นไปตามหลักวิทยาศาสตร์เพราะเราต้องโหลดสคริปต์หลายครั้งเพื่อให้ได้ข้อมูลที่วิเคราะห์ และไม่ได้เฉพาะเจาะจงกับคลาสหรือฟังก์ชันบางอย่าง . เรียกว่า.
คลาสอื่นในไลบรารี PEAR::Benchmark ที่เรียกว่า Benchmark_Iterator สามารถแก้ปัญหานี้ได้เป็นอย่างดี โดยสามารถแสดงข้อมูลการวิเคราะห์สำหรับฟังก์ชันหรือเมธอดคลาสเฉพาะได้ จุดประสงค์คือเพื่อให้ได้ผลลัพธ์ที่สม่ำเสมอจากการทดสอบ เพราะเรารู้ว่าถ้าเรารันสคริปต์หนึ่งครั้งและใช้เวลารัน 10 วินาที ไม่ได้หมายความว่าจะใช้เวลา 10 วินาทีในการรันทุกครั้งเสมอไป
ไม่ว่าในกรณีใด เรามาดูตัวอย่างบางส่วนกัน:
// โค้ดสำหรับเชื่อมต่อกับฐานข้อมูล
include_once("DB.php");
$dsn = อาร์เรย์(
'phptype' => 'mysql',
'hostspec' => 'localhost',
'ฐานข้อมูล' => 'database_name',
'ชื่อผู้ใช้' => 'ชื่อผู้ใช้',
'รหัสผ่าน' => 'รหัสผ่าน'
-
$dbh = DB::connect($dsn);
ฟังก์ชั่น getCreatedDate($id)
-
$dbh ทั่วโลก;
> $stmt = "เลือก create_date จากผู้ใช้ WHERE id=$id";
// ใช้ PEAR::DB ที่นี่
$created_date = $dbh-> getOne($stmt);
ถ้า ((PEAR::isError($created_date)) ||
(ว่าง($created_date))) {
กลับเท็จ;
} อื่น {
กลับ $created_date;
-
-
include_once 'เกณฑ์มาตรฐาน/Iterate.php';
$bench = เกณฑ์มาตรฐานใหม่_Iterate;
//เรียกใช้ฟังก์ชัน getDate 10 ครั้ง
$bench-> run(10, 'getCreatedDate', 1);
//พิมพ์ข้อมูลการวิเคราะห์
print_r($ม้านั่ง->รับ());
-
การรันโค้ดข้างต้นจะให้ผลลัพธ์ที่คล้ายกับดังต่อไปนี้:
อาร์เรย์
-
[1] => 0.055413007736206
[2] => 0.0012860298156738
[3] => 0.0010279417037964
[4] => 0.00093603134155273
[5] => 0.00094103813171387
[6] => 0.00092899799346924
[7] => 0.0010659694671631
[8] => 0.00096404552459717
[9] => 0.0010690689086914
[10] => 0.00093603134155273
[หมายถึง] => 0.0064568161964417
[การวนซ้ำ] => 10
-
ตัวเลขข้างต้นง่ายต่อการเข้าใจ รายการเฉลี่ยแสดงถึงเวลาเฉลี่ยของการเรียกใช้ฟังก์ชัน getCreatedDate() 10 ครั้ง ในการทดสอบจริง คุณควรรันอย่างน้อย 1,000 ครั้ง แต่ผลลัพธ์จากตัวอย่างนี้ก็เพียงพอที่จะอธิบายปัญหาได้