0Pricing
PHP Academy · บทเรียน

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 level

JIT แบบฟังก์ชันเทียบกับแบบติดตาม

มีกลยุทธ์สองแบบ ได้แก่ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การทำงานของ Zend Engine
  2. การจัดการหน่วยความจำและการเก็บขยะ
  3. OPcache และการคอมไพล์ JIT
  4. การเขียนส่วนขยาย PHP พื้นฐานด้วย C
← กลับไปที่ PHP Academy