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

การหลีกเลี่ยงการลบโค้ดที่ไม่ก่อผล

Blackhole และสถานะ

การหลีกเลี่ยงการลบโค้ดที่ไม่ก่อผล เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

การหลีกเลี่ยงการลบโค้ดที่ไม่มีการใช้งาน

กับดักที่ใหญ่ที่สุดของการทดสอบประสิทธิภาพระดับย่อยคือการลบโค้ดที่ไม่มีการใช้งาน (DCE): หากคอมไพเลอร์แบบทันเวลาพิสูจน์ได้ว่าไม่มีการใช้ผลลัพธ์ มันจะลบการคำนวณนั้นออกไป จากนั้น Benchmark ของคุณก็จะไม่วัดอะไรเลย JMH มีเครื่องมือสองอย่างเพื่อป้องกันปัญหานี้ ได้แก่ การส่งคืนค่าและ Blackhole

กับดัก DCE

ลูปนี้คำนวณรากที่สองหนึ่งล้านครั้ง แต่ไม่เคยใช้ผลลัพธ์เลย คอมไพเลอร์อัจฉริยะจึงสามารถลบลูปทั้งหมดออกได้

public class Main {
    public static void main(String[] args) {
        long t = System.nanoTime();
        for (int i = 0; i < 1_000_000; i++) {
            double ignored = Math.sqrt(i); // result thrown away
        }
        System.out.println("ns: " + (System.nanoTime() - t));
    }
}

วิธีแก้ที่ 1: ส่งคืนผลลัพธ์

วิธีป้องกันที่ง่ายที่สุดคือส่งคืนค่าที่คำนวณได้จากเมธอด @Benchmark JMH จะใช้ค่าที่ส่งคืนทุกค่า ดังนั้น JVM จึงไม่สามารถพิสูจน์ได้ว่าค่านั้นไม่มีการใช้งาน

import org.openjdk.jmh.annotations.Benchmark;

public class Bench {
    @Benchmark
    public double sqrt() {
        return Math.sqrt(42.0); // returned -> consumed by JMH
    }
}

วิธีแก้ที่ 2: แบล็กโฮล

เมื่อ Benchmark สร้างค่าหลายค่า หรือเมื่อคุณไม่สามารถส่งคืนค่าเดียวได้ ให้แทรก Blackhole แล้วเรียกใช้ consume(...) แบล็กโฮลจะทำให้คอมไพเลอร์แบบทันเวลาเชื่อว่ามีการใช้ค่าทุกค่า โดยไม่ต้องเสียต้นทุนจากการทำงานจริง

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.infra.Blackhole;

public class Bench {
    @Benchmark
    public void manyValues(Blackhole bh) {
        for (int i = 0; i < 100; i++) {
            bh.consume(Math.sqrt(i));
        }
    }
}

ออบเจ็กต์ @State

คลาส @State จะเก็บอินพุตที่ไม่เปิดเผยรายละเอียดต่อตัวปรับให้เหมาะสม เพื่อป้องกันการพับค่าคงที่ JMH จะสร้างอินสแตนซ์ของคลาสนี้และส่งให้ Benchmark ของคุณ ขอบเขตอาจเป็น Thread, Benchmark (ใช้ร่วมกัน) หรือ Group

import org.openjdk.jmh.annotations.*;

public class Bench {
    @State(Scope.Thread)
    public static class Data {
        public int x = 21;
    }

    @Benchmark
    public int multiply(Data d) {
        return d.x * 2; // d.x is not a compile-time constant
    }
}

@Setup และ @TearDown

ภายในคลาส @State เมธอดที่มีคำอธิบายประกอบ @Setup จะทำงานก่อนการวัดผล และ @TearDown จะทำงานหลังจากนั้น Level จะควบคุมความถี่ ได้แก่ Trial (ครั้งเดียว), Iteration หรือ Invocation

import org.openjdk.jmh.annotations.*;

@State(Scope.Thread)
public class Data {
    int[] arr;
    @Setup(Level.Trial)
    public void init() {
        arr = new int[1000];
        for (int i = 0; i < arr.length; i++) arr[i] = i;
    }
}

หลีกเลี่ยงอินพุตค่าคงที่

อย่าป้อนค่าคงที่ที่เขียนตรง ๆ ให้กับเมธอดที่กำลังทดสอบโดยเด็ดขาด Math.sqrt(2.0) อาจถูกพับรวมเป็นค่าคงที่ได้ แต่ Math.sqrt(state.value) ไม่สามารถทำเช่นนั้นได้ ควรรับอินพุตจากฟิลด์ @State เสมอ

การคืนค่าหลายค่า

หากการทดสอบประสิทธิภาพของคุณสร้างผลลัพธ์สองค่าโดยธรรมชาติ คุณสามารถคืนค่าหนึ่งค่าแล้วส่งอีกค่าหนึ่งให้แบล็กโฮล หรือรวมผลลัพธ์ทั้งสองเข้าด้วยกันได้ หากปล่อยให้ค่าใดค่าหนึ่งไม่ได้ถูกใช้ ช่องโหว่จาก DCE ก็จะกลับมาอีกครั้ง

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.infra.Blackhole;

public class Bench {
    @Benchmark
    public int twoResults(Blackhole bh) {
        int a = 3 * 7;
        int b = 5 + 9;
        bh.consume(b);
        return a;
    }
}

โอเวอร์เฮดของแบล็กโฮล

แบล็กโฮลได้รับการออกแบบให้มีต้นทุนต่ำมากและป้องกันการปรับปรุงประสิทธิภาพที่อาจตัดทิ้งตัวมันเองได้ แต่ก็ไม่ได้ไม่มีต้นทุนโดยสิ้นเชิง สำหรับการทำงานที่รวดเร็วมาก ควรเลือกคืนค่าเพียงค่าเดียว และใช้แบล็กโฮลกับลูปหรือกรณีที่มีหลายค่า

ตรวจสอบความสมเหตุสมผลของตัวเลข

หากการทดสอบประสิทธิภาพรายงานเวลาเหลือน้อยจนเป็นไปไม่ได้ เช่น ต่ำกว่าหนึ่งนาโนวินาทีสำหรับงานจริง ให้สงสัยว่าอาจเกิด DCE หรือการพับค่าคงที่ ตรวจสอบอีกครั้งว่ามีการคืนค่าหรือใช้ผลลัพธ์ และอินพุตมาจาก @State

นำทุกอย่างมารวมกัน

การทดสอบประสิทธิภาพที่รัดกุมควรอ่านอินพุตจากออบเจ็กต์ @State ทำงานที่ต้องการ แล้วคืนค่าผลลัพธ์ด้วย return หรือส่งผลลัพธ์ให้ Blackhole.consume ด้วยแนวปฏิบัติสามข้อนี้ DCE และการพับค่าคงที่จะไม่สามารถทำให้การวัดของคุณคลาดเคลื่อนได้

ตรวจสอบความเข้าใจ

ทดสอบความเข้าใจของคุณเกี่ยวกับการป้องกันการตัดโค้ดที่ไม่มีการใช้งาน

ทบทวน

คุณได้เรียนรู้วิธีทำให้การทดสอบประสิทธิภาพมีความน่าเชื่อถือ:

  • การตัดโค้ดที่ไม่มีการใช้งานจะลบการคำนวณที่ไม่ได้ใช้
  • คืนค่าผลลัพธ์เพียงค่าเดียว เพื่อให้ JMH รับผลลัพธ์นั้นไปใช้
  • ใช้ Blackhole.consume กับลูปและกรณีที่มีหลายค่า
  • ออบเจ็กต์ @State ทำให้อินพุตไม่ชัดเจน จึงป้องกันการพับค่าคงที่
  • @Setup / @TearDown ใช้เตรียมและล้างสถานะในระดับที่เลือก

คำถามที่พบบ่อย

บทเรียน “การหลีกเลี่ยงการลบโค้ดที่ไม่ก่อผล” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การหลีกเลี่ยงการลบโค้ดที่ไม่ก่อผล” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การหลีกเลี่ยงการลบโค้ดที่ไม่ก่อผล”

Blackhole และสถานะ คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การหลีกเลี่ยงการลบโค้ดที่ไม่ก่อผล” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม

ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

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

  1. เหตุใดจึงใช้ JMH
  2. การเขียนการวัดประสิทธิภาพ
  3. การอุ่นเครื่องและรอบการทำงาน
  4. การหลีกเลี่ยงการลบโค้ดที่ไม่ก่อผล
← กลับไปที่ Java Academy