(บทความ PHP) รูปแบบและเงื่อนไงของการวน loop ที่ดี
จากที่ผมได้พบมาพอสมควรเกี่ยวกับเรื่องการวน loop ในหลายๆโปรแกรมแล้วพบว่ามันไม่ค่อยดีเท่าไร
ก่อนอื่นก็มีเรื่องจะต้องเล่าว่า
ผมเป็นพวกที่ชอบดูซอร์สโค้ดที่ผู้อื่นเขียน เพื่อหาแนวคิดใหม่ๆเสมอๆ เพื่อพัฒนาด้านแนวคิดใหม่ๆในการวางโครงสร้างเพื่อเขียนโปรแกรม
เนื่องมาจากผมคิดว่าการได้ศึกษาแนวคิดของผู้อื่น จะทำให้เราได้ึรับความสามารถในการวิเคราะห์ในการเขียนโปรแกรมเพิ่มขึ้น
เพราะผมถือว่า
ความรู้ต้องใช้คู่กับปัญญา
มีปัญญาแต่ไม่มีความรู้
ก็ใช้ปัญญาอันนั้นหาความรู้ได้
และก็จะสามารถใช้ปัญญาและคววามรู้นั้นให้เกิดผลได้
แต่ถ้าหากมีความรู้แต่ไร้ปัญญา
ก็ยากที่จะใช้ความรู้ให้เกิดผลได้
ทำให้ผมโหลดโปรแกรมจากทั่วสารทิศมาศึกษาแนวคิดในการเขียนโปรแกรมอยู่เสมอๆ
และก็ทำให้ผมได้เจอสิ่งผิดๆ ที่เป็นวิธียอดฮิต ในการเขียนโปรแกรม ในหลายๆภาษา(แต่ในที่นี้ผมจะยกตัวอย่างเป็น PHP ละกัน จะได้ืทดลองกันได้ง่ายๆ)
นั่นก็คือ
การเรียกฟังก์ชั่นขณะวนลูป ก่อนอื่นหลายๆคนอาจยังไม่รู้ว่า ลูป หรือ (loop) คืออะไร (ทั้งๆที่ใช้มาตั้งนาน)
loop ก็คือคำสั่งที่ใช้ในการวน กระทำชุดคำสั่งที่กำหนด ซ้ำไปซ้ำมาตามเงื่อนไข
ตั่วอย่างเช่นคำสั่ง for , while เป็นต้น
ที่พบว่าเขียนผิดกันบ่อยๆ มีโค้ดประมาณนี้
for($i=0;$i<
strlen($str);$i++)
{
}
ตรงสีแดงๆนี่ไงที่ผิด หลายๆคนบอกก็ถูกแล้วนี่ มันผิดตรงไหน จะว่าไม่ผิดมันก็ไม่ผิดนะครับ (จะบอกว่าไม่ผิดแต่ไม่ควรก็น่าจะได้)
ตามความเป็นจริงแล้วมันก็ไม่ผิด แต่นี่คือวิธีเขียนที่ทำให้ประมวลผลช้ากว่าที่ควรจะเป็น
แล้วทำไมล่ะ มันถึงช้ากว่าที่ควร ?
อธิบายแบบง่ายๆ ก็ลองนึกย้อนไปดีๆครับ ว่าฟังก์ชั่นคืออะไร และ ตัวแปรคืออะไร
จากตัวอย่าง strlen() เป็นฟังก์ชั่น ที่ใช้นับตัวอักษร แล้วจากตัวอย่างนี้เอง ลองสังเกตดีๆ ว่า
strlen จะต้องประมวลผลทุกๆรอบที่วนลูปเพื่อนำไปตรวจสอบกับตัวแปร $iวิธีที่ดีกว่าคือ
$str_length = strlen($str);
for($i=0;$i<
$str_length;$i++)
{
}
แล้วมันดีกว่ายังไงน่ะหรือ ลองดูให้ดีๆนะครับ มีการเรียกใช้ strlen ครั้งเดียว ที่เหลือก็เปรียบเทียบตัวแปร $str_length กับตัวแปร $i เท่าันั้น
ใครยังนึกภาำพไม่ออกบ้าง งั้นผมจะอธิบายให้ง่ายกว่านั้น
สมมติว่า คุณเป็นพนักงานบัญชีของบริษัทหนึ่ง มีเจ้านาย 5 คน วันนึงเจ้านายคนแรกเข้ามาถามว่า "เดือนนี้บริษัทเราได้กำไรเท่าไร"
คุณก็เลยคำนวนอยู่สักพัก แล้วจึงตอบเจ้านายไป "100,577,799,335 บาทครับ" พอเจ้านายคนที่สองเข้ามาถาม เหมือนกันเป๊ะ ว่า
"เดือนนี้บริษัทเราได้กำไรเท่าไร" คุณก็นั่งคำนวนใหม่ และก็ตอบกลับไปแบบเดิม "100,577,799,335 บาทครับ" และก็เป็นเช่นนี้จนครบ 5 คน
>>>นั่นคือการเปรีัยบเทียบกับโค้ดตัวแรก
แต่ถ้าหากคุณจดมันไว้ตั้งแต่ตอนที่เจ้านายคนแรกเข้ามาถาม แล้วพอเจ้านายคนต่อๆไปมาถามก็แค่ตอบไปตามที่จดเอาไว้ จะทำให้คุณไม่ต้องไปคำนวนใหม่เลย
>> นี่คือการเปรียบเทียบกับโค้ดที่สอง
คำถามที่พบเจอบ่อยๆคือ ? แล้วมันจะเร็วกว่าจริงๆเหรอ แล้วถ้าเร็วกว่าจะเร็วแค่ไหน
มันก็เท่าความยาวในการวนลูปนั่นแหละครับ ยิ่งวนมากครั้งจะยิ่งเห็นความต่าง
วันนี้ผมจึงได้เขียนสคริปสำหรับทดสอบมาให้ท่านทั้งหลายได้ดูความแตกต่างระหว่างการเขียนทั้งสองแบบ โดยมีโค้ดดังนี้
ชุดที่ 1 การเขียนที่ไม่ควร
<?php
// เก็บค่าตัวแปรเวลา เมื่อวินาทีที่สคริปเริ่มทำงาน
$time = microtime();
$time = explode(" ", $time);
$time = $time[1] + $time[0];
$start = $time;
?>
<?php
$mc = microtime();
$str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for($i=0;$i<strlen($str);$i++)
{
// loop เปล่าๆ
}
?>
<?php
// เก็บค่าตัวแปรเวลา เมื่อวินาทีสคริปหยุดทำงาน และ นำไปลบกับเวลาที่สคริปเริ่มทำงาน จะได้เวลาที่ใช้ในการประมวลผลคำสั่ง
$time = microtime();
$time = explode(" ", $time);
$time = $time[1] + $time[0];
$finish = $time;
$totaltime = ($finish - $start);
printf ("ใช้เวลาประมวลผลหน้านี้ %f วินาที.", $totaltime);
?>
และ โค้ดที่ถูกต้อง
<?php
// เก็บค่าตัวแปรเวลา เมื่อวินาทีที่สคริปเริ่มทำงาน
$time = microtime();
$time = explode(" ", $time);
$time = $time[1] + $time[0];
$start = $time;
?>
<?php
$mc = microtime();
$str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
$strl = strlen($str);
for($i=0;$i<$strl;$i++)
{
// loop เปล่าๆ
}
?>
<?php
// เก็บค่าตัวแปรเวลา เมื่อวินาทีสคริปหยุดทำงาน และ นำไปลบกับเวลาที่สคริปเริ่มทำงาน จะได้เวลาที่ใช้ในการประมวลผลคำสั่ง
$time = microtime();
$time = explode(" ", $time);
$time = $time[1] + $time[0];
$finish = $time;
$totaltime = ($finish - $start);
printf ("ใช้เวลาประมวลผลหน้านี้ %f วินาที.", $totaltime);
?>
ลองรันทั้งสองดูนะครับจะเห็นความแตกต่างกันด้านความเร็ว ประมาณ 0.000010 วินาที
แต่อย่าเพิ่งคิดว่า "แค่ 0.000010 วินาทีเอง ไม่เป็นไรหรอก" เพราะยิ่งข้อมูลที่เป็นเงื่อนไขเยอะ การวนลูปก็ยิ่งเยอะ ถ้าเป็นโปรแกรมใหญ่ๆ ความเร็วคงต่างกันถึง 1 ถึง 5 วิเลยทีเดียว
ฉะนั้นโปรดคิดให้ดีก่อนลงมือเขียน เพราะ "โค้ดสั้นกว่าไม่ได้แปลว่าจะประมวลผลเร็วกว่าเสมอไป ต้องดูความเหมาะสมด้วย"
นี่ไม่ใช่แค่สคริปของคนทั่วไปเท่านั้นที่เป็นเช่นนี้ แต่สคริปของคนที่ถูกเรียกว่าเทพ(ซึ่งคำว่าเทพนี้สมัยปัจจุบันหมายถึงคนเก่ง) ในด้านการเขียนโปรแกรมก็เป็นเหมือนกัน
คนที่ไม่ค่อยเก่งก็เขียนเพราะไม่รู้ แต่เทพ บางท่านอาจจะคิดว่า Interpreter มันจะ optimize ให้ละมั้ง อะไรทำนองนี้ ฉะนั้นขอให้ท่านลองย้อนกลับไปมองนิดนึงว่า
"ถ้าท่านเป็นคนเขียน php ท่านจะให้ Interpreter มันไปยุ่งกับ เงื่อนไขของลูปที่เป็นรูปแบบของฟังก์ชั่นหรือ" อย่าลืมไปว่า ถ้าเป็นฟังก์ชั่น พารามิเตอร์ของฟังก์ชั่นอาจเกิดความเปลี่ยนแปลงได้เสมอ
นั่นอาจประทบต่อค่าที่ออกมาจากฟังก์ชั่น ซึ่งจะนำมาเปรียบเทียบกันได้ ฉะนั้นไม่ว่าภาษาใดก็ไม่มีการ optimize ในส่วนนี้ป.ล. ในการโพสโค้ดตัวอย่างผมใช้ [ quote ] เพราะ [ code ] ไม่แสดงผลภาษาไทย
ไว้วันหลังถ้าว่างจะเขียนเรื่องอื่นๆอีกครับ วันนี้เอาไว้แค่นี้ก่อน
อ้อลืมไป จากตัวอย่างไม่ได้หมายถึงคำสั่ง strlen เท่านั้นนะครับ หมายถึงคำสั่งอื่นๆด้วย แค่ยก strlen มาเป็นตัวอย่างให้จินตนาการออกกันเท่านั้นเอง
ผิดพลาดประการใดก็ขออภัยด้วยครับ
ขอบคุณครับ