OPcache และการคอมไพล์ JIT
เร่ง PHP ด้วยการแคชไบต์โค้ดและ JIT
OPcache และการคอมไพล์ JIT เป็นบทเรียน PHP Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน PHP Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส PHP Academy มีบทเรียนทั้งหมด 4 บทเรียน
การแคชผลการคอมไพล์
OPcache จัดเก็บรหัสคำสั่งที่คอมไพล์แล้วไว้ในหน่วยความจำใช้ร่วมกัน ทำให้ PHP ไม่ต้องวิเคราะห์คำ วิเคราะห์ไวยากรณ์ และคอมไพล์ใหม่ในทุกคำขอ นอกจากนี้ JIT (ตั้งแต่ PHP 8.0) ยังสามารถคอมไพล์รหัสคำสั่งที่ทำงานบ่อยเป็นรหัสเครื่องเนทีฟได้ ทั้งสองอย่างนี้เป็นรากฐานหลักของประสิทธิภาพ PHP
บทเรียนนี้ครอบคลุมการกำหนดค่า OPcache การโหลดล่วงหน้า และการปรับแต่ง JIT
OPcache ทำอะไรบ้าง
อาร์เรย์รหัสคำสั่งที่คอมไพล์แล้วของแต่ละไฟล์จะถูกแคชไว้ในส่วนหน่วยความจำใช้ร่วมกันที่เวิร์กเกอร์ FPM ทั้งหมดใช้งานร่วมกัน คำขอที่พบข้อมูลในแคชจะนำรหัสคำสั่งกลับมาใช้โดยตรง OPcache ยังเรียกใช้ตัวเพิ่มประสิทธิภาพ (การคำนวณค่าคงที่ล่วงหน้า การตัดโค้ดที่ไม่มีทางทำงาน และการรวมรหัสคำสั่ง) ในครั้งแรกที่คอมไพล์ไฟล์
; Core OPcache config (php.ini)
opcache.enable = 1
opcache.memory_consumption = 256 ; MB of shared memory
opcache.interned_strings_buffer = 16 ; MB for interned strings
opcache.max_accelerated_files = 20000 ; cap on cached scriptsการตรวจสอบเวลาแก้ไข
validate_timestamps กำหนดว่า OPcache จะตรวจสอบเวลาแก้ไขของไฟล์อีกครั้งหรือไม่ ในสภาพแวดล้อมพัฒนาให้เปิดใช้งานไว้พร้อมกำหนด revalidate_freq ให้สั้น ส่วนในสภาพแวดล้อมจริงให้ตั้งค่าเป็น0 เพื่อไม่ให้ PHP ตรวจสอบไฟล์ด้วยสถิติระบบเลย และให้ติดตั้งเวอร์ชันใหม่ด้วยการล้างแคช (หรือสร้างอิมเมจใหม่)
; Production: never re-stat files
opcache.validate_timestamps = 0
; Development: check every 2 seconds
; opcache.validate_timestamps = 1
; opcache.revalidate_freq = 2ตรวจสอบแคช
opcache_get_status() รายงานอัตราการพบแคช การใช้หน่วยความจำ และสคริปต์ที่แคชไว้ ส่วน opcache_get_configuration() จะแสดงการตั้งค่า อัตราการพบแคชต่ำหรือการเริ่มระบบใหม่บ่อยครั้งหมายความว่าหน่วยความจำมีน้อยเกินไปหรือมีไฟล์มากเกินไป
<?php
if (function_exists('opcache_get_status')) {
$s = opcache_get_status(false);
if ($s) {
printf("hits: %d\n", $s['opcache_statistics']['hits']);
printf("misses: %d\n", $s['opcache_statistics']['misses']);
printf("hit %%: %.2f\n", $s['opcache_statistics']['opcache_hit_rate']);
printf("used: %.1f MB\n", $s['memory_usage']['used_memory'] / 1048576);
} else {
echo "OPcache enabled but no status (likely CLI)\n";
}
} else {
echo "OPcache not available\n";
}
?>การโหลดล่วงหน้า
การโหลดล่วงหน้า (PHP 7.4 ขึ้นไป) จะคอมไพล์ชุดคลาสและฟังก์ชันหนึ่งครั้งเมื่อเซิร์ฟเวอร์เริ่มทำงาน แล้วเก็บไว้ในหน่วยความจำอย่างถาวร เพื่อให้ทุกคำขอใช้งานได้โดยไม่ต้องโหลดอัตโนมัติหรือเชื่อมโยงใหม่ในแต่ละคำขอ ให้กำหนด opcache.preload เป็นสคริปต์ที่เรียกใช้ไฟล์เพื่อเตรียมแคช
; php.ini
opcache.preload = /app/preload.php
opcache.preload_user = www-dataเขียนสคริปต์โหลดล่วงหน้า
สคริปต์โหลดล่วงหน้าจะทำงานในกระบวนการหลัก ใช้ opcache_compile_file() เพื่อโหลดคลาสโดยไม่เรียกใช้คลาส หรือใช้ require โดยตรง เฟรมเวิร์กสามารถสร้างรายการโหลดล่วงหน้าได้ นี่คือลักษณะของรายการดังกล่าว
<?php
// preload.php — runs once at startup
$dir = '/app/src';
$rii = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir)
);
foreach ($rii as $file) {
if ($file->getExtension() === 'php') {
// Compiles + links the class into shared memory
opcache_compile_file($file->getPathname());
}
}
?>เริ่มใช้ JIT
แม้จะมีรหัสคำสั่งที่แคชไว้แล้ว VM ก็ยังตีความรหัสเหล่านั้นอยู่ JIT จะคอมไพล์ลำดับรหัสคำสั่งที่ทำงานบ่อยเป็นคำสั่งเนทีฟของ CPU เพื่อตัดต้นทุนการกระจายงานของ VM ผลลัพธ์จะดีขึ้นมากสำหรับโค้ดตัวเลขที่ใช้ CPU หนัก แต่ดีขึ้นเพียงเล็กน้อยสำหรับแอปเว็บที่ทำงานด้านอินพุต/เอาต์พุตเป็นหลัก ซึ่งใช้เวลาไปกับฐานข้อมูลและเครือข่าย ไม่ใช่ CPU
กำหนดค่า JIT
JIT ทำงานอยู่ภายใน OPcache ดังนั้นต้องเปิด OPcache ไว้ opcache.jit_buffer_size จะจัดสรรพื้นที่สำหรับรหัสเครื่องที่สร้างขึ้น (ค่า 0 จะปิด JIT) ส่วน opcache.jit เป็นโหมดตัวเลข 4 หลักที่ควบคุมเงื่อนไขการเริ่มทำงานและกลยุทธ์การเพิ่มประสิทธิภาพ
; Enable JIT (requires opcache.enable=1)
opcache.jit_buffer_size = 128M
opcache.jit = tracing ; alias for 1254, the common default
; The 4 digits CRTO mean:
; C - CPU optimization flags
; R - register allocation
; T - trigger (when to JIT)
; O - optimization levelJIT แบบฟังก์ชันเทียบกับแบบติดตาม
มีกลยุทธ์สองแบบ ได้แก่ JIT แบบฟังก์ชัน (โหมด 1205) ซึ่งคอมไพล์ฟังก์ชันทั้งชุดเมื่อเรียกใช้ครั้งแรก และ JIT แบบติดตาม (1254 ซึ่งเป็นชื่อแทนเริ่มต้น tracing) ที่วิเคราะห์ข้อมูลการทำงานและคอมไพล์วงรอบหรือลำดับการทำงานที่ทำงานบ่อย วิธีหลังมักให้ผลดีกว่าเพราะปรับเฉพาะตามชนิดข้อมูลที่พบ การติดตามเป็นค่าเริ่มต้นที่แนะนำ
; Tracing JIT (recommended) — compiles hot traces
opcache.jit = tracing
; Function JIT — compiles entire functions when first called
; opcache.jit = function
; Disable JIT but keep opcode cache
; opcache.jit_buffer_size = 0วัดผลกระทบของ JIT
JIT แสดงประสิทธิภาพได้ดีในวงรอบคำนวณตัวเลขที่กระชับ การทดสอบประสิทธิภาพแบบทำงานได้ในตัวนี้ (วงรอบด้านในที่คล้าย Mandelbrot) เป็นงานที่ใช้ CPU หนักประเภทที่ JIT สามารถลดเวลาทำงานลงได้มาก ให้เรียกใช้ทั้งโดยมีและไม่มี jit_buffer_size เพื่อเปรียบเทียบ
<?php
function mandelEscape(float $cr, float $ci, int $max): int {
$zr = 0.0; $zi = 0.0; $n = 0;
while ($n < $max && ($zr * $zr + $zi * $zi) <= 4.0) {
$t = $zr * $zr - $zi * $zi + $cr;
$zi = 2.0 * $zr * $zi + $ci;
$zr = $t;
$n++;
}
return $n;
}
$start = hrtime(true);
$sum = 0;
for ($y = 0; $y < 200; $y++) {
for ($x = 0; $x < 200; $x++) {
$sum += mandelEscape($x / 100 - 2, $y / 100 - 1, 256);
}
}
printf("sum=%d time=%.2f ms\n", $sum, (hrtime(true) - $start) / 1e6);
?>เมื่อไม่ควรคาดหวังผลเพิ่มจาก JIT
สำหรับคำขอทั่วไปที่เรียกใช้ฐานข้อมูล สร้างแม่แบบ และส่งคืน JSON CPU จะทำการคำนวณดิบไม่มาก JIT อาจเพิ่มประสิทธิภาพได้เพียงไม่กี่เปอร์เซ็นต์หรือไม่เพิ่มเลย ควรให้ความสำคัญกับ OPcache การโหลดล่วงหน้า และการใช้ฐานข้อมูลหรือแคชที่ดีเสียก่อน ควรปรับแต่ง JIT สำหรับการประมวลผลภาพ คณิตศาสตร์ ตัววิเคราะห์ และโค้ดอื่นที่ใช้การคำนวณหนัก
ตรวจสอบความเข้าใจ
การโหลดล่วงหน้าให้อะไรแก่คุณบ้างที่การแคชด้วย OPcache แบบปกติไม่มี
สรุป
OPcache จะแคชอาร์เรย์รหัสคำสั่งที่คอมไพล์แล้วในหน่วยความจำใช้ร่วมกันและเรียกใช้ตัวเพิ่มประสิทธิภาพ ในระบบจริงให้ตั้งค่า validate_timestamps=0 และกำหนดขนาด memory_consumption/max_accelerated_files ให้เหมาะสม การโหลดล่วงหน้าจะเก็บคลาสที่เลือกไว้ในหน่วยความจำตั้งแต่เริ่มต้น JIT (อยู่ภายใน OPcache และต้องใช้ jit_buffer_size) จะคอมไพล์โค้ดที่ทำงานบ่อยเป็นคำสั่งเนทีฟ ช่วยได้มากกับคณิตศาสตร์ที่ใช้ CPU หนัก แต่ช่วยได้น้อยกับแอปเว็บที่ทำงานด้านอินพุต/เอาต์พุตเป็นหลัก ใช้ opcache_get_status() เพื่อตรวจสอบ
คำถามที่พบบ่อย
บทเรียน “OPcache และการคอมไพล์ JIT” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “OPcache และการคอมไพล์ JIT” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส PHP Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส PHP Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “OPcache และการคอมไพล์ JIT”
เร่ง PHP ด้วยการแคชไบต์โค้ดและ JIT คุณปฏิบัติ PHP Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน PHP Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน PHP Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “OPcache และการคอมไพล์ JIT” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน PHP Academy นี้ได้ไหม
ได้ บทเรียน PHP Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การทำงานของ Zend Engine
- การจัดการหน่วยความจำและการเก็บขยะ
- OPcache และการคอมไพล์ JIT
- การเขียนส่วนขยาย PHP พื้นฐานด้วย C