ฉันต้องคิดถึงรหัสเครื่องที่คอมไพล์เมื่อฉันเขียนรหัสหรือไม่?


20

ตัวอย่างเช่นฉันได้รับรหัสต่อไปนี้:

auto z = [](int x) -> int {
    if (x > 0) {
        switch (x) {
            case 2: return 5;
            case 3: return 6;
            default: return 1;
            }
        }
    return 0;
    };

และต่อมาฉันเรียกสิ่งนี้หลายครั้ง ในรหัส asm ฉันเห็นสายภายนอกด้วยแลมบ์ดา .... บางสิ่งบางอย่าง ... มันกลายเป็นเรื่องง่ายที่จะอ่านและฉันคิดว่ามันอาจทำให้ประสิทธิภาพ ดังนั้นฉันอาจชนะในการเขียนโปรแกรม meta แต่ฉันเสียในการดีบัก asm และประสิทธิภาพหรือไม่ ฉันควรหลีกเลี่ยงฟีเจอร์ภาษาที่ทันสมัยมาโครและด้านการเขียนโปรแกรมเมตาอื่น ๆ เพื่อให้แน่ใจในประสิทธิภาพและการแก้ไขข้อบกพร่องอย่างง่ายหรือไม่?


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

15
คุณไม่จำเป็นต้องแก้จุดบกพร่องรหัสแอสเซมบลีเว้นแต่ว่าคุณกำลังแสดงเส้นทางที่สำคัญ นอกจากนี้ "รหัสสะอาด"! = "การแสดงที่ดี"
BЈовић

โปรดแก้ไขการเยื้องของคุณ ฉันพยายามที่จะทำ แต่ดูเหมือนว่าคุณไม่สามารถแก้ไขเพียงช่องว่าง
Christoffer Hammarström

3
@Heather: คุณดูเหมือนจะใช้สไตล์ Ratliffซึ่งฉันไม่เคยเห็นมาก่อนและหาอ่านยาก แน่นอนว่าเป็นหนึ่งในคนที่ไม่ค่อยมีคนรู้จัก ความประทับใจของฉันคือคุณไม่ได้เยื้องอย่างถูกต้อง ไม่เป็นไรถ้าหากคุณอ่านได้ฉันก็ไม่เห็นด้วย
Christoffer Hammarström

1
รหัสifซ้ำซ้อนอย่างสมบูรณ์และในขณะที่คอมไพเลอร์อาจจับได้ว่าไม่มีเหตุผลที่จะล่อลวงการคาดการณ์ของสาขาที่ไม่ดี
dmckee

คำตอบ:


59

ฉันต้องคิดถึงรหัสเครื่องที่คอมไพล์เมื่อฉันเขียนรหัสหรือไม่?

ไม่ไม่ใช่เมื่อคุณเขียนรหัสในครั้งแรกและไม่ประสบปัญหาประสิทธิภาพที่แท้จริงและวัดได้ สำหรับภารกิจส่วนใหญ่นี่เป็นกรณีมาตรฐาน คิดเร็วเกินไปที่เกี่ยวกับการเพิ่มประสิทธิภาพที่เรียกว่า "การเพิ่มประสิทธิภาพก่อนวัยอันควร" และมีเหตุผลที่ดีว่าทำไม D. Knuth เรียกว่า"รากของความชั่วร้ายทั้งหมด"

ใช่เมื่อคุณวัดคอขวดประสิทธิภาพที่แท้จริงและพิสูจน์ได้และคุณระบุแลมบ์ดาที่เฉพาะเจาะจงว่าเป็นสาเหตุของปัญหา ในกรณีนี้มันเป็นความคิดที่ดีที่จะระลึกถึง"กฎของ abstractions รั่ว"ของ Joel Spolsky และคิดเกี่ยวกับสิ่งที่อาจเกิดขึ้นในระดับ asm แต่ระวังคุณอาจประหลาดใจว่าการเพิ่มประสิทธิภาพจะมีขนาดเล็กเพียงใดเมื่อคุณแทนที่แลมบ์บิวด์ด้วยโครงสร้างภาษา "ไม่ทันสมัย" (อย่างน้อยเมื่อใช้คอมไพเลอร์ C ++ ที่เหมาะสม)


2
+1 กระชับแม่นยำและง่ายต่อการติดตามหมอทั่วไปดีใจที่เรามีคุณอยู่ที่นี่
Jimmy Hoffa

เห็นด้วยคำตอบที่ชัดเจนมาก
cnd

8

ทางเลือกระหว่างแลมบ์ดาและฟังก์ชั่นระดับคือการแลกเปลี่ยน

กำไรจากแลมบ์ดานั้นส่วนใหญ่เป็นประโยคโดยลดจำนวนสำเร็จรูปและอนุญาตให้เขียนโค้ดที่เกี่ยวข้องกับแนวคิดที่จะเขียนแบบอินไลน์ภายในฟังก์ชั่นที่จะใช้มัน (ทันทีหรือในภายหลัง)

ประสิทธิภาพการทำงานที่ชาญฉลาดนี้ไม่แย่ไปกว่าคลาส functorซึ่งเป็นโครงสร้าง C ++ หรือคลาสที่มี "เมธอด" เดียว ในความเป็นจริงคอมไพเลอร์ปฏิบัติกับแลมบ์ดาไม่ต่างไปจากคลาสนักสะสมที่สร้างขึ้นจากเบื้องหลัง

// define the functor method somewhere
struct some_computer_generated_gibberish_0123456789
{
    int operator() (int x) const
    {
        if (x == 2) return 5;
        if (x == 3) return 6;
        return 0;
    }
};

// make a call
some_computer_generated_gibberish_0123456789 an_instance_of_0123456789;
int outputValue = an_instance_of_0123456789(inputValue);

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

int some_computer_generated_gibberish_0123456789_method_more_gibberish(int x)
{
    if (...) return ...;
    return ...;
}

การดีบักโค้ด C ++ ที่ไม่สำคัญโดยใช้ disassembler นั้นเป็นงานที่ยากเสมอ นี่เป็นเรื่องจริงที่มีหรือไม่มีการใช้แลมบ์ดา นี่คือสาเหตุที่เกิดจากการเพิ่มประสิทธิภาพของรหัสที่ซับซ้อนโดยคอมไพเลอร์ C ++ ที่ส่งผลให้เกิดการเรียงลำดับใหม่, interleaving และกำจัดรหัสที่ตายแล้ว

แง่มุมของชื่อ mangling นั้นค่อนข้างไม่ปลอดภัยและการรองรับตัวดีบั๊กสำหรับแลมบ์ดายังอยู่ในช่วงเริ่มต้น สามารถหวังได้ว่าการสนับสนุนการดีบักเกอร์จะดีขึ้นเมื่อเวลาผ่านไป

ปัจจุบันวิธีที่ดีที่สุดในการดีบักรหัสแลมบ์ดาคือการใช้ดีบักเกอร์ที่รองรับการตั้งค่าเบรกพอยต์ในระดับซอร์สโค้ดเช่นโดยการระบุชื่อไฟล์ต้นฉบับและหมายเลขบรรทัด


3

หากต้องการเพิ่มคำตอบโดย @DocBrown โปรดจำไว้ว่าในวันนี้ CPU มีราคาถูก แต่แรงงานมีราคาแพง

ในค่าใช้จ่ายโดยรวมของโปรแกรมฮาร์ดแวร์มักจะเล็กน้อยเมื่อเทียบกับค่าใช้จ่ายในการบำรุงรักษาซึ่งเป็นส่วนที่แพงที่สุดของโครงการทั่วไป (ยิ่งกว่าการพัฒนา)

ดังนั้นรหัสของคุณจำเป็นต้องปรับปรุงการบำรุงรักษาให้เหนือสิ่งอื่นใดยกเว้นเมื่อประสิทธิภาพมีความสำคัญ (และต้องพิจารณาการบำรุงรักษาด้วย)


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

@ gnash117 - ใช่คุณพูดถูกถ้ารหัสถูกเรียกใช้หลายครั้ง ขอบคุณที่ชี้นำสิ่งนี้ ในกรณีดังกล่าวการบันทึกรหัสไว้อย่างชัดเจนจะทำให้สามารถรักษาได้ในขณะที่ปรับปรุงประสิทธิภาพ
Paddy Landau

"แรงงานแพง" - ถูกต้อง เวลาของลูกค้าของคุณสำคัญมากและมักมีราคาแพง
Cerad
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.