ประสิทธิภาพ C ++ เทียบกับ Java / C #


119

ความเข้าใจของฉันคือ C / C ++ สร้างโค้ดเนทีฟเพื่อรันบนสถาปัตยกรรมเครื่องเฉพาะ ในทางกลับกันภาษาเช่น Java และ C # ทำงานบนเครื่องเสมือนซึ่งแยกสถาปัตยกรรมดั้งเดิมออกไป ดูเหมือนจะเป็นไปไม่ได้ที่ Java หรือ C # จะจับคู่ความเร็วของ C ++ เนื่องจากขั้นตอนกลางนี้อย่างไรก็ตามฉันได้รับแจ้งว่าคอมไพเลอร์ล่าสุด ("ฮอตสปอต") สามารถบรรลุความเร็วนี้หรือสูงกว่านั้นได้

บางทีนี่อาจเป็นคำถามเกี่ยวกับคอมไพเลอร์มากกว่าคำถามด้านภาษา แต่ใครก็ได้สามารถอธิบายเป็นภาษาอังกฤษแบบธรรมดาได้ว่าภาษาเครื่องเสมือนเหล่านี้จะทำงานได้ดีกว่าภาษาแม่หรือไม่


Java และ C # สามารถทำการปรับให้เหมาะสมตามวิธีที่แอปพลิเคชันทำงานโดยใช้รหัสตามที่มีอยู่ในรันไทม์ เช่นสามารถอินไลน์โค้ดในไลบรารีที่ใช้ร่วมกันซึ่งสามารถเปลี่ยนแปลงได้จริงในขณะที่โปรแกรมกำลังทำงานและยังคงถูกต้อง
Peter Lawrey

การวัดจริงบางอย่างเพื่อตรวจสอบก่อนอ่านทฤษฎีที่ไม่สม่ำเสมอจำนวนมากในคำตอบเหล่านี้: shootout.alioth.debian.org/u32/…
Justicle

คำตอบ:


178

โดยทั่วไป C # และ Java สามารถเร็วขึ้นหรือเร็วขึ้นได้เนื่องจากคอมไพเลอร์ JIT ซึ่งเป็นคอมไพเลอร์ที่รวบรวม IL ของคุณในครั้งแรกที่ดำเนินการ - สามารถทำการปรับแต่งที่โปรแกรมคอมไพล์ C ++ ไม่สามารถทำได้เนื่องจากสามารถค้นหาเครื่องได้ สามารถระบุได้ว่าเครื่องเป็น Intel หรือ AMD; Pentium 4, Core Solo หรือ Core Duo; หรือหากรองรับ SSE4 เป็นต้น

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

นอกจากนี้คุณสมบัติภาษาบางอย่างยังอนุญาตให้คอมไพเลอร์ใน C # และ Java ตั้งสมมติฐานเกี่ยวกับโค้ดของคุณซึ่งอนุญาตให้เพิ่มประสิทธิภาพบางส่วนออกไปซึ่งไม่ปลอดภัยสำหรับคอมไพเลอร์ C / C ++ เมื่อคุณเข้าถึงพอยน์เตอร์มีการเพิ่มประสิทธิภาพมากมายที่ไม่ปลอดภัย

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

ตอนนี้ฉันไม่สามารถพูดกับ Java ในจุดต่อไปนี้ได้ แต่ฉันรู้ว่าตัวอย่างเช่น C # จะลบเมธอดและการเรียกเมธอดเมื่อรู้ว่าเนื้อหาของเมธอดว่างเปล่า และจะใช้ตรรกะแบบนี้ตลอดโค้ดของคุณ

ดังที่คุณเห็นมีหลายสาเหตุที่การใช้งาน C # หรือ Java บางอย่างจะเร็วขึ้น

ตอนนี้ทั้งหมดกล่าวแล้วการเพิ่มประสิทธิภาพเฉพาะสามารถทำได้ใน C ++ ซึ่งจะทำลายทุกสิ่งที่คุณสามารถทำได้กับ C # โดยเฉพาะอย่างยิ่งในขอบเขตกราฟิกและทุกเวลาที่คุณอยู่ใกล้กับฮาร์ดแวร์ พอยน์เตอร์ทำสิ่งมหัศจรรย์ที่นี่

ขึ้นอยู่กับสิ่งที่คุณกำลังเขียนฉันจะไปกับอย่างใดอย่างหนึ่ง แต่ถ้าคุณกำลังเขียนบางอย่างที่ไม่ได้ขึ้นอยู่กับฮาร์ดแวร์ (ไดรเวอร์วิดีโอเกม ฯลฯ ) ฉันจะไม่กังวลเกี่ยวกับประสิทธิภาพของ C # (พูดถึง Java ไม่ได้อีกแล้ว) มันจะทำได้ดี

หนึ่งในฝั่ง Java @Swatiชี้ให้เห็นบทความที่ดี:

https://www.ibm.com/developerworks/library/j-jtp09275


เหตุผลของคุณเป็นของปลอม - โปรแกรม C ++ ถูกสร้างขึ้นสำหรับสถาปัตยกรรมเป้าหมายพวกเขาไม่จำเป็นต้องสลับที่รันไทม์
Justicle

3
@Justicle คอมไพเลอร์ c ++ ที่ดีที่สุดของคุณจะนำเสนอสำหรับสถาปัตยกรรมที่แตกต่างกันมักจะเป็น x86, x64, ARM และอะไรก็ตาม ตอนนี้คุณสามารถบอกให้ใช้คุณลักษณะเฉพาะ (เช่น SSE2) และหากคุณโชคดีมันจะสร้างรหัสสำรองบางอย่างหากคุณสมบัตินั้นไม่พร้อมใช้งาน แต่ก็เป็นเรื่องที่ละเอียดที่สุดเท่าที่จะทำได้ แน่นอนว่าไม่มีความเชี่ยวชาญขึ้นอยู่กับขนาดแคชและอะไร
Voo

4
ดูshootout.alioth.debian.org/u32/…สำหรับตัวอย่างของทฤษฎีนี้ที่ไม่เกิดขึ้น
Justicle

1
พูดตามตรงนี่เป็นหนึ่งในคำตอบที่แย่ที่สุด มันไม่มีมูลความจริงฉันสามารถพลิกกลับได้ การวางนัยทั่วไปมากเกินไปโดยไม่รู้ตัวมากเกินไป (การเพิ่มประสิทธิภาพฟังก์ชันว่างเปล่าเป็นเพียงส่วนเล็ก ๆ ของภูเขาน้ำแข็ง) คอมไพเลอร์ C ++ สุดหรูหนึ่งตัวมี: เวลา ความหรูหราอีกอย่าง: ไม่มีการบังคับใช้การตรวจสอบ แต่พบมากขึ้นในการstackoverflow.com/questions/145110/c-performance-vs-java-c/...
Sebastian Mach

1
@Orion เอเดรียนโอเคตอนนี้เราเต็มวงแล้ว ... ดูshootout.alioth.debian.org/u32/…สำหรับตัวอย่างของทฤษฎีนี้ที่ไม่เกิดขึ้น กล่าวอีกนัยหนึ่งแสดงให้เราเห็นว่าทฤษฎีของคุณสามารถพิสูจน์ได้ว่าถูกต้องก่อนที่จะกล่าวถึงการคาดเดาที่คลุมเครือ
Justicle

197

JIT กับ Static Compiler

ดังที่ได้กล่าวไปแล้วในโพสต์ก่อนหน้านี้ JIT สามารถรวบรวม IL / bytecode เป็นโค้ดเนทีฟได้ที่รันไทม์ ค่าใช้จ่ายนั้นถูกกล่าวถึง แต่ยังไม่สรุป:

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

แน่นอนว่า C # (หรือ Java หรือ VB) มักจะสร้างโซลูชันที่ทำงานได้และมีประสิทธิภาพได้เร็วกว่า C ++ (หากเป็นเพียงเพราะ C ++ มีความหมายที่ซับซ้อนและไลบรารีมาตรฐาน C ++ ในขณะที่น่าสนใจและมีประสิทธิภาพนั้นค่อนข้างแย่เมื่อเทียบกับแบบเต็ม ขอบเขตของไลบรารีมาตรฐานจาก. NET หรือ Java) ดังนั้นโดยปกติความแตกต่างระหว่าง C ++ และ. NET หรือ Java JIT จะไม่ปรากฏแก่ผู้ใช้ส่วนใหญ่และสำหรับไบนารีที่มีความสำคัญคุณยังสามารถเรียกใช้การประมวลผล C ++ ได้ จาก C # หรือ Java (แม้ว่าการเรียกแบบเนทีฟแบบนี้อาจมีค่าใช้จ่ายค่อนข้างสูง) ...

การเขียนโปรแกรม C ++

โปรดทราบว่าโดยปกติแล้วคุณกำลังเปรียบเทียบโค้ดรันไทม์ C ++ กับโค้ดที่เทียบเท่าใน C # หรือ Java แต่ C ++ มีคุณสมบัติอย่างหนึ่งที่สามารถทำงานได้ดีกว่า Java / C # นอกกรอบนั่นคือการเขียนโปรแกรมแม่แบบ: การประมวลผลโค้ดจะดำเนินการในเวลาคอมไพล์ (ดังนั้นจึงเพิ่มเวลาในการรวบรวมอย่างมาก) ทำให้รันไทม์เป็นศูนย์ (หรือเกือบเป็นศูนย์)

ฉันยังเห็นผลกระทบในชีวิตจริงในเรื่องนี้ (ฉันเล่นกับแนวคิดเท่านั้น แต่ถึงตอนนั้นความแตกต่างคือวินาทีของการดำเนินการสำหรับ JIT และเป็นศูนย์สำหรับ C ++) แต่สิ่งนี้ควรค่าแก่การกล่าวถึงควบคู่ไปกับการตั้งโปรแกรมเมทาโพรแกรมของเทมเพลตแฟล็ก จิ๊บจ๊อย ...

แก้ไข 2011-06-10:ใน C ++ การเล่นกับประเภทจะเสร็จสิ้นในเวลาคอมไพล์ซึ่งหมายถึงการสร้างรหัสทั่วไปที่เรียกรหัสที่ไม่ใช่ทั่วไป (เช่นตัวแยกวิเคราะห์ทั่วไปจากสตริงเป็นประเภท T เรียก API ไลบรารีมาตรฐานสำหรับประเภท T ที่รู้จัก และการทำให้ parser สามารถขยายได้ง่ายโดยผู้ใช้) นั้นง่ายมากและมีประสิทธิภาพมากในขณะที่ Java หรือ C # ที่เทียบเท่านั้นเจ็บปวดที่สุดในการเขียนและจะช้ากว่าและแก้ไขได้เสมอเมื่อรันไทม์แม้ว่าจะทราบประเภทในเวลาคอมไพล์ก็ตาม หมายความว่าความหวังเดียวของคุณคือการให้ JIT แทรกซึมเข้าไปในทุกสิ่ง

...

แก้ไข 2011-09-20:ทีมที่อยู่เบื้องหลัง Blitz ++ ( หน้าแรก , Wikipedia ) ไปในทางนั้นและเห็นได้ชัดว่าเป้าหมายของพวกเขาคือการบรรลุผลการดำเนินงานของ FORTRAN ในการคำนวณทางวิทยาศาสตร์โดยการย้ายจากการรันไทม์ไปจนถึงเวลาคอมไพล์ให้มากที่สุดเท่าที่จะเป็นไปได้ . ดังนั้น "ฉันยังเห็นผลกระทบในชีวิตจริงในส่วนนี้ " ที่ฉันเขียนไว้ข้างต้นดูเหมือนจะมีอยู่ในชีวิตจริง

การใช้หน่วยความจำ Native C ++

C ++ มีการใช้งานหน่วยความจำที่แตกต่างจาก Java / C # ดังนั้นจึงมีข้อดี / ข้อบกพร่องที่แตกต่างกัน

ไม่ว่าการเพิ่มประสิทธิภาพ JIT จะไม่มีอะไรเร็วเท่ากับการเข้าถึงตัวชี้โดยตรงไปยังหน่วยความจำ (ลองละเว้นไปชั่วขณะแคชโปรเซสเซอร์ ฯลฯ ) ดังนั้นหากคุณมีข้อมูลที่ต่อเนื่องกันในหน่วยความจำการเข้าถึงผ่านตัวชี้ C ++ (เช่นตัวชี้ C ... ขอให้ Caesar ครบกำหนด) จะเร็วกว่าใน Java / C # หลายเท่า และ C ++ มี RAII ซึ่งทำให้การประมวลผลง่ายกว่าใน C # หรือแม้แต่ใน Java มาก C ++ ไม่จำเป็นต้องusingกำหนดขอบเขตการมีอยู่ของวัตถุ และ C ++ ไม่มีfinallyอนุประโยค นี่ไม่ใช่ข้อผิดพลาด

:-)

และแม้จะมีโครงสร้างเหมือนดั้งเดิมของ C # แต่วัตถุ C ++ "บนสแต็ก" จะไม่เสียค่าใช้จ่ายใด ๆ ในการจัดสรรและการทำลายและไม่จำเป็นต้องมี GC ในการทำงานในเธรดอิสระในการทำความสะอาด

สำหรับการแยกส่วนหน่วยความจำตัวจัดสรรหน่วยความจำในปี 2008 ไม่ใช่ตัวจัดสรรหน่วยความจำแบบเก่าจากปี 1980 ที่มักจะเปรียบเทียบกับ GC: การจัดสรร C ++ ไม่สามารถย้ายในหน่วยความจำได้จริง แต่แล้วเช่นเดียวกับระบบไฟล์ Linux: ใครต้องการฮาร์ดดิสก์ การจัดเรียงข้อมูลเมื่อไม่เกิดการแยกส่วน? การใช้ตัวจัดสรรที่เหมาะสมสำหรับงานที่เหมาะสมควรเป็นส่วนหนึ่งของชุดเครื่องมือสำหรับนักพัฒนา C ++ ตอนนี้การเขียนตัวจัดสรรไม่ใช่เรื่องง่ายแล้วพวกเราส่วนใหญ่มีสิ่งที่ดีกว่าที่ต้องทำและสำหรับการใช้งานส่วนใหญ่ RAII หรือ GC นั้นดีเกินพอ

แก้ไข 2011-10-04:สำหรับตัวอย่างเกี่ยวกับตัวจัดสรรที่มีประสิทธิภาพ: บนแพลตฟอร์ม Windows ตั้งแต่ Vista, Low Fragmentation Heapถูกเปิดใช้งานโดยค่าเริ่มต้น สำหรับเวอร์ชันก่อนหน้า LFH สามารถเปิดใช้งานได้โดยเรียกใช้ฟังก์ชัน WinAPI HeapSetInformation ) ในระบบปฏิบัติการอื่นจะมีการจัดเตรียมตัวจัดสรรสำรองไว้ให้ (ดูhttps://secure.wikimedia.org/wikipedia/en/wiki/Mallocสำหรับรายชื่อ)

ตอนนี้โมเดลหน่วยความจำค่อนข้างซับซ้อนมากขึ้นด้วยการเพิ่มขึ้นของเทคโนโลยีมัลติคอร์และมัลติเธรด ในช่องนี้ฉันเดาว่า. NET มีข้อได้เปรียบและ Java ที่ฉันได้รับการบอกกล่าวว่าถือเป็นจุดสูงสุด เป็นเรื่องง่ายที่แฮ็กเกอร์ "บนเครื่องโลหะ" บางคนจะยกย่องรหัส "ใกล้เครื่อง" ของเขา แต่ตอนนี้มันค่อนข้างยากที่จะสร้างการประกอบด้วยมือที่ดีกว่าการปล่อยให้คอมไพเลอร์ทำงาน สำหรับ C ++ คอมไพเลอร์มักจะดีกว่าแฮ็กเกอร์ตั้งแต่ทศวรรษที่ผ่านมา สำหรับ C # และ Java สิ่งนี้ง่ายยิ่งขึ้น

ถึงกระนั้น C ++ 0x มาตรฐานใหม่จะกำหนดรูปแบบหน่วยความจำอย่างง่ายให้กับคอมไพเลอร์ C ++ ซึ่งจะทำให้โค้ดหลายกระบวนการ / ขนาน / เธรดที่มีประสิทธิภาพเป็นมาตรฐาน (และทำให้ง่ายขึ้น) ใน C ++ และทำให้การเพิ่มประสิทธิภาพง่ายขึ้นและปลอดภัยสำหรับคอมไพเลอร์ แต่แล้วเราจะเห็นในอีกไม่กี่ปีข้างหน้าว่าคำสัญญานั้นเป็นจริงหรือไม่

C ++ / CLI เทียบกับ C # / VB.NET

หมายเหตุ: ในส่วนนี้ฉันกำลังพูดถึง C ++ / CLI นั่นคือ C ++ ที่โฮสต์โดย. NET ไม่ใช่ C ++ ดั้งเดิม

สัปดาห์ที่แล้วฉันมีการฝึกอบรมเกี่ยวกับการเพิ่มประสิทธิภาพ. NET และพบว่าคอมไพเลอร์แบบคงที่มีความสำคัญมาก สำคัญกว่า JIT

โค้ดเดียวกันที่คอมไพล์ใน C ++ / CLI (หรือบรรพบุรุษของมันคือ Managed C ++) อาจเร็วกว่าโค้ดเดียวกันที่ผลิตใน C # (หรือ VB.NET ซึ่งคอมไพเลอร์สร้าง IL เหมือนกันมากกว่า C #)

เนื่องจากคอมไพเลอร์แบบคงที่ของ C ++ สามารถสร้างโค้ดที่ปรับให้เหมาะสมแล้วได้ดีกว่า C #

ตัวอย่างเช่นฟังก์ชัน inlining ใน. NET จะ จำกัด เฉพาะฟังก์ชันที่มีความยาว bytecode น้อยกว่าหรือเท่ากับ 32 ไบต์ ดังนั้นโค้ดบางตัวใน C # จะสร้างตัวเข้าถึงขนาด 40 ไบต์ซึ่ง JIT จะไม่อินไลน์เลย รหัสเดียวกันใน C ++ / CLI จะสร้างตัวเข้าถึงขนาด 20 ไบต์ซึ่ง JIT จะอยู่ในบรรทัด

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

เหตุผลนี้ถูกคาดเดาว่าเป็นความจริงที่ว่าคอมไพเลอร์ C ++ / CLI ได้รับประโยชน์จากเทคนิคการเพิ่มประสิทธิภาพมากมายจากคอมไพเลอร์ดั้งเดิมของ C ++

ข้อสรุป

ฉันรัก C ++

แต่เท่าที่ฉันเห็น C # หรือ Java ล้วนเป็นทางออกที่ดีกว่า ไม่ใช่เพราะเร็วกว่า C ++ แต่เป็นเพราะเมื่อคุณเพิ่มคุณสมบัติของพวกเขาพวกเขาจะมีประสิทธิผลมากขึ้นต้องการการฝึกอบรมน้อยลงและมีไลบรารีมาตรฐานที่สมบูรณ์มากกว่า C ++ และสำหรับโปรแกรมส่วนใหญ่ความแตกต่างของความเร็ว (ไม่ทางใดก็ทางหนึ่ง) จะเล็กน้อย ...

แก้ไข (2011-06-06)

ประสบการณ์ของฉันเกี่ยวกับ C # /. NET

ตอนนี้ฉันมีการเข้ารหัส C # ระดับมืออาชีพเกือบ 5 เดือน (ซึ่งรวมถึง CV ของฉันแล้วเต็มไปด้วย C ++ และ Java และสัมผัส C ++ / CLI)

ฉันเล่นกับ WinForms (อะแฮ่ม ... ) และ WCF (เจ๋ง!) และ WPF (เจ๋ง !!!! ทั้งผ่าน XAML และ C # ดิบ WPF นั้นง่ายมากฉันเชื่อว่า Swing ไม่สามารถเปรียบเทียบกับมันได้) และ C # 4.0

ข้อสรุปคือแม้ว่าจะง่าย / เร็วกว่าในการสร้างโค้ดที่ทำงานใน C # / Java มากกว่าใน C ++ แต่การสร้างโค้ดที่แข็งแกร่งปลอดภัยและมีประสิทธิภาพใน C # (และยากกว่าใน Java) มากกว่าใน C ++ เหตุผลมากมาย แต่สามารถสรุปได้โดย:

  1. Generics ไม่ได้มีประสิทธิภาพเท่าเทมเพลต ( พยายามเขียนวิธีการแยกวิเคราะห์ทั่วไปที่มีประสิทธิภาพ (จากสตริงถึง T) หรือการเพิ่มประสิทธิภาพที่เทียบเท่ากับการเพิ่ม :: lexical_cast ใน C # เพื่อทำความเข้าใจปัญหา )
  2. RAII ยังคงไม่ตรงกัน ( GC ยังคงรั่วไหลได้ (ใช่ฉันต้องจัดการปัญหานั้น) และจะจัดการเฉพาะหน่วยความจำแม้แต่ C # usingก็ไม่ง่ายและทรงพลังเพราะการเขียนการกำจัดการใช้งานที่ถูกต้องเป็นเรื่องยาก )
  3. C # readonlyและ Java finalไม่มีประโยชน์เท่า C ++const ( ไม่มีทางที่คุณจะเปิดเผยข้อมูลที่ซับซ้อนแบบอ่านอย่างเดียว (เช่น Tree of Nodes) ใน C # โดยไม่ต้องทำงานมากในขณะที่เป็นคุณลักษณะในตัวของ C ++ ข้อมูลที่ไม่เปลี่ยนรูปเป็นโซลูชันที่น่าสนใจ แต่ไม่ใช่ทุกอย่างที่จะไม่เปลี่ยนรูปได้ดังนั้นมันจึงไม่เพียงพอด้วยซ้ำ)

ดังนั้น C # ยังคงเป็นภาษาที่น่ารื่นรมย์ตราบเท่าที่คุณต้องการบางสิ่งที่ใช้ได้ผล แต่เป็นภาษาที่น่าหงุดหงิดในขณะที่คุณต้องการสิ่งที่ใช้ได้ผลเสมอและปลอดภัย

Java นั้นน่าผิดหวังมากยิ่งขึ้นเนื่องจากมีปัญหาเดียวกันกับ C # และอื่น ๆ : การขาดusingคีย์เวิร์ดของ C # ที่เทียบเท่าเพื่อนร่วมงานที่มีทักษะสูงของฉันใช้เวลามากเกินไปในการตรวจสอบให้แน่ใจว่าทรัพยากรที่ได้รับการปลดปล่อยอย่างถูกต้องในขณะที่ C ++ ที่เทียบเท่าจะมี เป็นเรื่องง่าย (โดยใช้ตัวทำลายและตัวชี้อัจฉริยะ)

ดังนั้นฉันเดาว่าการเพิ่มผลผลิตของ C # / Java สามารถมองเห็นได้สำหรับโค้ดส่วนใหญ่ ... จนถึงวันที่คุณต้องการโค้ดให้สมบูรณ์แบบที่สุด วันนั้นคุณจะรู้ความเจ็บปวด (คุณจะไม่เชื่อว่าสิ่งที่ถามจากเซิร์ฟเวอร์และแอป GUI ของเรา ... )

เกี่ยวกับ Java ฝั่งเซิร์ฟเวอร์และ C ++

ฉันยังคงติดต่อกับทีมเซิร์ฟเวอร์ (ฉันทำงานร่วมกัน 2 ปีก่อนที่จะกลับไปที่ทีม GUI) ที่อีกด้านหนึ่งของอาคารและฉันได้เรียนรู้สิ่งที่น่าสนใจ

ปีที่ผ่านมามีแนวโน้มที่จะมีการกำหนดให้แอปเซิร์ฟเวอร์ Java มาแทนที่แอปเซิร์ฟเวอร์ C ++ รุ่นเก่าเนื่องจาก Java มีเฟรมเวิร์ก / เครื่องมือมากมายและง่ายต่อการบำรุงรักษาปรับใช้และอื่น ๆ ฯลฯ

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

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

ข้อสรุป

ไม่มีอะไรง่ายอย่างที่คิด

Java และ C # เป็นภาษาที่ยอดเยี่ยมพร้อมด้วยไลบรารีและเฟรมเวิร์กมาตรฐานที่กว้างขวางซึ่งคุณสามารถเขียนโค้ดได้อย่างรวดเร็วและได้ผลลัพธ์ในไม่ช้า

แต่เมื่อคุณต้องการพลังดิบการเพิ่มประสิทธิภาพที่ทรงพลังและเป็นระบบการสนับสนุนคอมไพเลอร์ที่แข็งแกร่งคุณสมบัติภาษาที่ทรงพลังและความปลอดภัยที่สมบูรณ์ Java และ C # ทำให้ยากที่จะชนะเปอร์เซ็นต์สุดท้ายที่ขาดหายไป แต่มีคุณภาพที่สำคัญที่คุณต้องอยู่เหนือคู่แข่ง

ราวกับว่าคุณต้องการเวลาน้อยลงและนักพัฒนาที่มีประสบการณ์น้อยกว่าใน C # / Java เมื่อเทียบกับ C ++ ในการสร้างโค้ดคุณภาพโดยเฉลี่ย แต่ในทางกลับกันช่วงเวลาที่คุณต้องการโค้ดคุณภาพที่ยอดเยี่ยมสมบูรณ์แบบทันใดนั้นก็จะได้ผลลัพธ์ที่ง่ายและเร็วขึ้น ใน C ++

แน่นอนว่านี่เป็นการรับรู้ของฉันเองบางทีอาจ จำกัด เฉพาะความต้องการเฉพาะของเรา

แต่ถึงกระนั้นมันก็เป็นสิ่งที่เกิดขึ้นในปัจจุบันทั้งในทีม GUI และทีมฝั่งเซิร์ฟเวอร์

แน่นอนฉันจะอัปเดตโพสต์นี้หากมีสิ่งใหม่เกิดขึ้น

แก้ไข (2011-06-22)

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

[... ] เวอร์ชัน Java น่าจะเป็นเวอร์ชันที่ใช้งานง่ายที่สุด แต่ยากที่สุดในการวิเคราะห์ประสิทธิภาพ โดยเฉพาะผลกระทบจากการเก็บขยะนั้นซับซ้อนและยากที่จะปรับแต่ง "

แหล่งที่มา:

แก้ไข (2011-09-20)

"คำที่กำลังดำเนินอยู่ใน Facebook คือ ' โค้ด C ++ ที่เขียนขึ้นอย่างมีเหตุผลทำงานได้เร็ว ' ซึ่งเน้นย้ำถึงความพยายามอย่างมากที่ใช้ในการเพิ่มประสิทธิภาพโค้ด PHP และ Java ในทางตรงกันข้ามโค้ด C ++ นั้นเขียนยากกว่าในภาษาอื่น ๆ แต่โค้ดที่มีประสิทธิภาพคือ [เขียนภาษา C ++ ง่ายกว่าภาษาอื่น] มาก "

- Herb Sutterที่// build /อ้างถึงAndrei Alexandrescu

แหล่งที่มา:


8
คุณแก้ไขหลังจาก 5 เดือนของ C # อธิบายถึงประสบการณ์ของฉันเอง (เทมเพลตดีกว่า const ดีกว่า RAII) +1 ทั้งสามยังคงเป็นคุณสมบัตินักฆ่าส่วนตัวของฉันสำหรับ C ++ (หรือ D ซึ่งฉันยังไม่มีเวลา)
Sebastian Mach

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

"การเล่นกับประเภทเสร็จสิ้นในเวลาคอมไพล์ ... การเทียบเท่าใน Java หรือ C # นั้นเจ็บปวดที่สุดในการเขียนและมักจะช้ากว่าและได้รับการแก้ไขเมื่อรันไทม์แม้ว่าจะทราบประเภทในเวลาคอมไพล์ก็ตาม" ใน C # นั่นเป็นเพียงความจริงสำหรับประเภทการอ้างอิงและไม่เป็นความจริงสำหรับชนิดค่า
JD

1
"ไม่ว่าการเพิ่มประสิทธิภาพ JIT จะไม่มีอะไรเร็วเท่ากับการเข้าถึงตัวชี้โดยตรงไปยังหน่วยความจำ ... หากคุณมีข้อมูลที่ต่อเนื่องกันในหน่วยความจำการเข้าถึงผ่านตัวชี้ C ++ (เช่นตัวชี้ C ... ขอให้ Caesar ครบกำหนด) จะไปครั้ง เร็วกว่าใน Java / C # " ผู้คนสังเกตว่า Java เอาชนะ C ++ ในการทดสอบ SOR จากเกณฑ์มาตรฐาน SciMark2 อย่างแม่นยำเนื่องจากตัวชี้ขัดขวางการปรับแต่งที่เกี่ยวข้องกับนามแฝง blogs.oracle.com/dagastine/entry/sun_java_is_faster_than
JD

นอกจากนี้ที่น่าสังเกตว่า. NET พิมพ์ความเชี่ยวชาญเฉพาะทางของยาสามัญข้ามไลบรารีที่เชื่อมโยงแบบไดนามิกหลังจากการเชื่อมโยงในขณะที่ C ++ ไม่สามารถทำได้เนื่องจากเทมเพลตต้องได้รับการแก้ไขก่อนการเชื่อมโยง และเห็นได้ชัดว่า generics ที่ได้เปรียบใหญ่มีมากกว่าเทมเพลตคือข้อความแสดงข้อผิดพลาดที่เข้าใจได้
JD

48

เมื่อใดก็ตามที่ฉันพูดถึงประสิทธิภาพที่มีการจัดการเทียบกับประสิทธิภาพที่ไม่มีการจัดการฉันชอบที่จะชี้ไปที่ซีรีส์ Rico (และ Raymond) ได้เปรียบเทียบเวอร์ชัน C ++ และ C # ของพจนานุกรมภาษาจีน / อังกฤษ การค้นหาโดย Googleนี้จะช่วยให้คุณอ่านด้วยตัวคุณเอง แต่ฉันชอบบทสรุปของ Rico

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

  • เขียนไฟล์ I / O ของเขาเอง
  • เขียนคลาสสตริงของเขาเอง
  • เขียนผู้จัดสรรของเขาเอง
  • เขียนแผนที่ระหว่างประเทศของเขาเอง

แน่นอนว่าเขาใช้ไลบรารีระดับล่างที่มีอยู่เพื่อทำสิ่งนี้ แต่ก็ยังต้องทำงานอีกมาก คุณสามารถเรียกสิ่งที่เหลืออยู่ในโปรแกรม STL ได้หรือไม่? ฉันไม่คิดอย่างนั้นฉันคิดว่าเขาคงคลาส std :: vector ไว้ซึ่งท้ายที่สุดก็ไม่เคยเป็นปัญหาและเขายังคงใช้ฟังก์ชัน find ทุกอย่างหายไปหมดแล้ว

ดังนั้นคุณสามารถเอาชนะ CLR ได้อย่างแน่นอน Raymond สามารถทำให้โปรแกรมของเขาดำเนินไปได้เร็วขึ้น

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

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


3
ลิงก์เสียแล้วพบบทความที่กล่าวถึงที่นี่: blogs.msdn.com/b/ricom/archive/2005/05/10/416151.aspx
gjvdkamp

ก่อนอื่นถ้าเราดูโค้ดของ Raymond Chen เขาไม่เข้าใจ C ++ หรือโครงสร้างข้อมูลเป็นอย่างดี รหัสของเขาเกือบจะตรงสำหรับรหัส C ระดับต่ำแม้ในกรณีที่รหัส C ไม่มีประโยชน์ด้านประสิทธิภาพ (ดูเหมือนจะเป็นความไม่ไว้วางใจและอาจขาดความรู้เกี่ยวกับวิธีใช้โปรไฟล์) นอกจากนี้เขายังล้มเหลวในการเข้าใจวิธีการใช้พจนานุกรมแบบอัลกอริทึมที่ดีที่สุด (เขาใช้ std :: find เพื่อเห็นแก่พระคริสต์) หากมีอะไรดีๆเกี่ยวกับ Java, Python, C # และอื่น ๆ - ทั้งหมดนี้มีพจนานุกรมที่มีประสิทธิภาพมาก ...
stinky472

ความพยายามหรือแม้กระทั่ง std :: map จะมีประโยชน์มากกว่าสำหรับ C ++ หรือแม้แต่ตารางแฮช สุดท้ายพจนานุกรมคือประเภทของโปรแกรมที่ได้รับประโยชน์สูงสุดจากไลบรารีและเฟรมเวิร์กระดับสูง มันไม่ได้แสดงให้เห็นถึงความแตกต่างในภาษามากเท่ากับห้องสมุดที่เกี่ยวข้อง (ซึ่งฉันขอบอกอย่างมีความสุขว่า C # นั้นสมบูรณ์กว่ามากและมีเครื่องมือที่เหมาะกับงานมากกว่า) แสดงโปรแกรมที่จัดการหน่วยความจำขนาดใหญ่โดยเปรียบเทียบเช่นรหัสเมทริกซ์ / เวกเตอร์ขนาดใหญ่ นั่นจะจัดการเรื่องนี้ได้ค่อนข้างเร็วแม้ว่าในกรณีนี้ผู้เขียนโค้ดจะไม่รู้ว่าอะไร ...
stinky472

26

การคอมไพล์สำหรับการปรับแต่งซีพียูที่เฉพาะเจาะจงมักจะเกินจริง เพียงแค่ใช้โปรแกรมใน C ++ และคอมไพล์ด้วยการเพิ่มประสิทธิภาพสำหรับ pentium PRO และเรียกใช้บน pentium 4 จากนั้นคอมไพล์ใหม่ด้วยการปรับให้เหมาะสมสำหรับ pentium 4 ฉันผ่านช่วงบ่ายที่ยาวนานด้วยการทำหลายโปรแกรม ผลทั่วไป ?? โดยปกติประสิทธิภาพจะเพิ่มขึ้นน้อยกว่า 2-3% ดังนั้นข้อดีของ JIT ในเชิงทฤษฎีจึงแทบไม่มีเลย ความแตกต่างของประสิทธิภาพส่วนใหญ่สามารถสังเกตได้เมื่อใช้คุณสมบัติการประมวลผลข้อมูลสเกลาร์ซึ่งในที่สุดก็ต้องมีการปรับจูนด้วยตนเองเพื่อให้ได้ประสิทธิภาพสูงสุดอยู่ดี การเพิ่มประสิทธิภาพของการเรียงลำดับนั้นช้าและมีค่าใช้จ่ายสูงในการดำเนินการทำให้บางครั้งไม่เหมาะสมสำหรับ JIT อยู่ดี

ในโลกแห่งความเป็นจริงและแอปพลิเคชันจริง C ++ มักจะเร็วกว่า java เนื่องจากมีหน่วยความจำน้อยกว่าซึ่งส่งผลให้ประสิทธิภาพของแคชดีขึ้น

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


4
การคอมไพล์เพื่อเพิ่มประสิทธิภาพ CPU ไม่มากนัก แต่คุณกำลังคอมไพล์เพื่อเพิ่มประสิทธิภาพพา ธ รันไทม์ หากคุณพบว่าเมธอดมักถูกเรียกด้วยพารามิเตอร์เฉพาะคุณสามารถคอมไพล์รูทีนนั้นล่วงหน้าด้วยพารามิเตอร์นั้นเป็นค่าคงที่ซึ่งสามารถ (ในกรณีของบูลีนที่ควบคุมโฟลว์) แยกชิ้นงานขนาดมหึมาออกไป C ++ ไม่สามารถเข้าใกล้การเพิ่มประสิทธิภาพแบบนั้นได้
Bill K

1
ดังนั้น JIT จะทำอย่างไรในการคอมไพล์รูทีนใหม่เพื่อใช้ประโยชน์จากรันพา ธ ที่สังเกตได้และความแตกต่างนั้นสร้างความแตกต่างได้อย่างไร?
David Thornley

2
@ ฉันอาจจะผสมสองสิ่ง ... แต่การทำนายสาขาไม่ได้ทำในขณะดำเนินการในขั้นตอนการเรียนการสอนบรรลุเป้าหมายที่คล้ายกันโดยไม่ขึ้นกับภาษาหรือไม่?
Hardy

@ ยากใช่ CPU สามารถทำการทำนายสาขาได้โดยไม่คำนึงถึงภาษา แต่ไม่สามารถแยกการวนซ้ำทั้งหมดได้โดยสังเกตว่าลูปไม่มีผลกระทบใด ๆ นอกจากนี้ยังจะไม่สังเกตว่า mult (0) เป็นแบบต่อสายเพื่อคืนค่า 0 และเพียงแค่แทนที่การเรียกเมธอดทั้งหมดด้วย if (param == 0) result = 0; และหลีกเลี่ยงการเรียกใช้ฟังก์ชัน / วิธีการทั้งหมด C สามารถทำสิ่งเหล่านี้ได้หากคอมไพเลอร์มีภาพรวมที่ครอบคลุมเกี่ยวกับสิ่งที่เกิดขึ้น แต่โดยทั่วไปแล้วจะไม่มีข้อมูลเพียงพอในเวลาคอมไพล์
Bill K

21

JIT (Just In Time Compiling) สามารถทำได้อย่างรวดเร็วอย่างไม่น่าเชื่อเนื่องจากปรับให้เหมาะสมกับแพลตฟอร์มเป้าหมาย

ซึ่งหมายความว่าสามารถใช้ประโยชน์จากเคล็ดลับคอมไพเลอร์ใด ๆ ที่ CPU ของคุณรองรับได้ไม่ว่าผู้พัฒนาจะเขียนโค้ดบน CPU ใดก็ตาม

แนวคิดพื้นฐานของ. NET JIT ทำงานเช่นนี้ (ทำให้ง่ายขึ้นมาก):

การเรียกใช้เมธอดเป็นครั้งแรก:

  • รหัสโปรแกรมของคุณเรียกเมธอด Foo ()
  • CLR จะดูประเภทที่ใช้ Foo () และรับข้อมูลเมตาที่เกี่ยวข้อง
  • จากข้อมูลเมตา CLR จะรู้ว่าที่อยู่หน่วยความจำใดที่ IL (รหัสไบต์กลาง) ถูกเก็บไว้ใน
  • CLR จัดสรรบล็อกของหน่วยความจำและเรียกใช้ JIT
  • JIT รวบรวม IL เป็นโค้ดเนทีฟวางไว้ในหน่วยความจำที่จัดสรรแล้วเปลี่ยนตัวชี้ฟังก์ชันในข้อมูลเมตาประเภทของ Foo () ให้ชี้ไปที่โค้ดเนทีฟนี้
  • รันโค้ดเนทีฟ

การเรียกใช้เมธอดเป็นครั้งที่สอง:

  • รหัสโปรแกรมของคุณเรียกเมธอด Foo ()
  • CLR จะดูประเภทที่ใช้ Foo () และค้นหาตัวชี้ฟังก์ชันในข้อมูลเมตา
  • มีการรันโค้ดเนทีฟที่ตำแหน่งหน่วยความจำนี้

อย่างที่คุณเห็นครั้งที่ 2 เป็นกระบวนการเดียวกันกับ C ++ ยกเว้นข้อได้เปรียบของการเพิ่มประสิทธิภาพแบบเรียลไทม์

ที่กล่าวว่ายังมีปัญหาค่าใช้จ่ายอื่น ๆ ที่ทำให้ภาษาที่มีการจัดการช้าลง แต่ JIT ช่วยได้มาก


ยังไงซะโจนาธานฉันคิดว่ามีคนยังไม่ลงคะแนนของคุณ เมื่อฉันโหวตคุณคุณมี -1 ในโพสต์นี้
Brian R.Bondy

12

ฉันชอบคำตอบของOrion Adrianแต่มีอีกแง่มุมหนึ่ง

คำถามเดียวกันนี้เกิดขึ้นเมื่อหลายสิบปีก่อนเกี่ยวกับภาษาแอสเซมบลีเทียบกับภาษา "มนุษย์" เช่น FORTRAN และส่วนหนึ่งของคำตอบก็คล้ายกัน

ใช่โปรแกรม C ++ สามารถทำงานได้เร็วกว่า C # ในอัลกอริทึมใด ๆ (ที่ไม่สำคัญ?) แต่โปรแกรมใน C # มักจะเร็วหรือเร็วกว่าการใช้งานแบบ "ไร้เดียงสา" ใน C ++ และเวอร์ชันที่ปรับให้เหมาะสมใน C ++ จะใช้เวลาพัฒนานานขึ้นและอาจยังเอาชนะเวอร์ชัน C # ได้ด้วยระยะขอบที่น้อยมาก แล้วมันคุ้มจริงหรือ?

คุณจะต้องตอบคำถามนั้นทีละข้อ

ที่กล่าวว่าฉันเป็นแฟนของ C ++ มานานและฉันคิดว่ามันเป็นภาษาที่แสดงออกและทรงพลังอย่างเหลือเชื่อ - บางครั้งก็ไม่ได้รับการยอมรับ แต่ใน "ปัญหาในชีวิตจริง" หลาย ๆ อย่าง (สำหรับฉันโดยส่วนตัวนั่นหมายถึง "แบบที่ฉันได้รับค่าจ้างเพื่อแก้ปัญหา") C # จะทำให้งานเสร็จเร็วและปลอดภัยมากขึ้น

โทษที่ใหญ่ที่สุดที่คุณต้องจ่าย? โปรแกรม. NET และ Java จำนวนมากเป็นหน่วยความจำ ฉันเคยเห็นแอป. NET และ Java ใช้หน่วยความจำ "หลายร้อย" เมกะไบต์เมื่อโปรแกรม C ++ ที่มีความซับซ้อนใกล้เคียงกันแทบจะไม่ขีดข่วน "สิบ" ของ MB


7

ฉันไม่แน่ใจว่าคุณจะพบว่าโค้ด Java ทำงานเร็วกว่า C ++ บ่อยแค่ไหนแม้จะมี Hotspot แต่ฉันจะอธิบายว่ามันเกิดขึ้นได้อย่างไร

คิดว่าโค้ด Java ที่คอมไพล์แล้วเป็นภาษาเครื่องที่ตีความสำหรับ JVM เมื่อโปรเซสเซอร์ Hotspot สังเกตเห็นว่าจะมีการใช้โค้ดบางส่วนของโค้ดที่คอมไพล์แล้วหลายครั้งจะทำการเพิ่มประสิทธิภาพให้กับรหัสเครื่อง เนื่องจากแอสเซมบลีการปรับแต่งด้วยมือมักจะเร็วกว่าโค้ดที่คอมไพล์ C ++ อยู่เสมอจึงสามารถคิดได้ว่าโค้ดเครื่องที่ปรับแต่งด้วยโปรแกรมจะไม่เลวร้ายเกินไป

ดังนั้นสำหรับโค้ดที่ซ้ำซากมากฉันจึงเห็นได้ว่า Hotspot JVM จะรัน Java ได้เร็วกว่า C ++ ที่ไหน ... จนกว่าการรวบรวมขยะจะเข้ามาเล่น :)


คุณช่วยขยายความเกี่ยวกับการยืนยันได้Since hand-tuning Assembly is almost always faster than C++ compiled codeหรือไม่? คุณหมายถึงอะไรโดย "hand-tuning Assembly" และ "C ++ compile code"?
paercebal

มันขึ้นอยู่กับแนวคิดที่ว่าเครื่องมือเพิ่มประสิทธิภาพของคอมไพเลอร์เป็นไปตามกฎและตัวเข้ารหัสไม่ทำ ดังนั้นจะมีโค้ดที่เครื่องมือเพิ่มประสิทธิภาพพบว่าไม่สามารถปรับให้เหมาะสมได้อย่างสมบูรณ์แบบในขณะที่มนุษย์สามารถทำได้โดยการดูภาพรวมที่ใหญ่ขึ้นหรือเรียนรู้เพิ่มเติมเกี่ยวกับสิ่งที่โค้ดกำลังทำอยู่ ฉันจะเพิ่มว่านี่เป็นความคิดเห็นที่เก่ากว่า 3 ปีและฉันรู้เกี่ยวกับ HotSpot มากกว่าที่เคยเป็นและฉันเห็นว่าการเพิ่มประสิทธิภาพแบบไดนามิกเป็นวิธีที่ดีมากในการทำให้โค้ดทำงานได้เร็วขึ้น
billjamesdev

1. การเพิ่มประสิทธิภาพจาก Hotspot หรือ JIT อื่น ๆ ยังคงเป็นการเพิ่มประสิทธิภาพคอมไพเลอร์ JIT มีข้อได้เปรียบเหนือคอมไพเลอร์แบบคงที่ในการอินไลน์ผลลัพธ์บางอย่าง (โค้ดที่เรียกบ่อย) หรือแม้กระทั่งทำการปรับให้เหมาะสมตามตัวประมวลผลที่เรียกใช้งาน แต่ก็ยังคงเป็นการเพิ่มประสิทธิภาพคอมไพเลอร์ . . 2. ฉันเดาว่าคุณกำลังพูดถึงการเพิ่มประสิทธิภาพอัลกอริทึมไม่ใช่ "การปรับแต่งการประกอบ" "การปรับแต่งการประกอบแบบแมนนวลโดยนักเขียนโค้ดของมนุษย์" ล้มเหลวในการสร้างผลลัพธ์ที่ดีกว่าการปรับแต่งคอมไพเลอร์นับเป็นเวลากว่าทศวรรษ ในความเป็นจริงมนุษย์ที่เล่นกับแอสเซมบลีมักจะทำให้การเพิ่มประสิทธิภาพลดลง ...
paercebal

ตกลงฉันเข้าใจว่าฉันใช้คำศัพท์ที่ไม่ถูกต้อง "การเพิ่มประสิทธิภาพคอมไพเลอร์" แทนที่จะเป็น "การเพิ่มประสิทธิภาพแบบคงที่" ฉันอยากจะชี้ให้เห็นว่าอย่างน้อยในอุตสาหกรรมเกมเมื่อเร็ว ๆ นี้สำหรับ PS2 เรายังคงใช้การประกอบแบบเข้ารหัสด้วยมือเพื่อ "เพิ่มประสิทธิภาพ" สำหรับชิปเฉพาะที่เรารู้ว่าอยู่บนคอนโซล cross-compiler สำหรับชิปใหม่เหล่านี้ยังไม่ซับซ้อนเท่าสำหรับสถาปัตยกรรม x86 กลับไปที่คำถามเดิมข้างต้น: JIT มีประโยชน์ในการวัดผลก่อนการปรับให้เหมาะสมซึ่งเป็นสิ่งที่ดี (TM)
billjamesdev

โปรดทราบว่า GC ที่ใช้งานจริงส่วนใหญ่ยังใช้แอสเซมเบลอร์ที่เขียนด้วยมือเนื่องจาก C / C ++ ไม่ได้ตัดมัน
JD

6

โดยทั่วไปของโปรแกรมอัลกอริทึมจะสำคัญมากขึ้นกับความเร็วของแอพลิเคชันของคุณมากกว่าที่ภาษา คุณสามารถใช้อัลกอริทึมที่ไม่ดีในภาษาใดก็ได้รวมถึง C ++ ด้วยเหตุนี้โดยทั่วไปคุณจะสามารถเขียนโค้ดได้การทำงานได้เร็วขึ้นในภาษาที่ช่วยให้คุณใช้อัลกอริทึมที่มีประสิทธิภาพมากขึ้น

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

นอกจากนี้ C ++ ยังใช้คุณสมบัติ "ใหม่" (สังเกตเครื่องหมายคำพูด) เช่นคอนเทนเนอร์ STL ตัวชี้อัตโนมัติ ฯลฯ - ดูไลบรารีเพิ่มเป็นต้น และในบางครั้งคุณอาจพบว่าวิธีที่เร็วที่สุดในการทำงานบางอย่างให้สำเร็จนั้นต้องใช้เทคนิคเช่นการคำนวณทางคณิตศาสตร์ของตัวชี้ซึ่งต้องห้ามในภาษาระดับสูงกว่าแม้ว่าพวกเขาจะอนุญาตให้คุณเรียกใช้ไลบรารีที่เขียนด้วยภาษาที่สามารถใช้งานได้ตามต้องการ .

สิ่งสำคัญคือการรู้ภาษาที่คุณใช้ API ที่เกี่ยวข้องสิ่งที่ทำได้และข้อ จำกัด คืออะไร


5

ฉันไม่รู้เหมือนกัน ... โปรแกรม Java ของฉันมักจะช้า :-) ฉันไม่เคยสังเกตว่าโปรแกรม C # ช้าเป็นพิเศษเลย


4

นี่คืออีกหนึ่งเกณฑ์มาตรฐานที่น่าสนใจซึ่งคุณสามารถทดลองใช้ด้วยตัวเองบนคอมพิวเตอร์ของคุณเอง

เปรียบเทียบ ASM, VC ++, C #, Silverlight, Java applet, Javascript, Flash (AS3)

การสาธิตความเร็วของปลั๊กอิน Roozz

โปรดทราบว่าความเร็วของจาวาสคริปต์นั้นแตกต่างกันไปมากขึ้นอยู่กับว่าเบราว์เซอร์ใดเรียกใช้งาน เช่นเดียวกับ Flash และ Silverlight เนื่องจากปลั๊กอินเหล่านี้ทำงานในกระบวนการเดียวกับเบราว์เซอร์โฮสติ้ง แต่ปลั๊กอิน Roozz เรียกใช้ไฟล์. exe มาตรฐานซึ่งทำงานในกระบวนการของตนเองดังนั้นความเร็วจึงไม่ได้รับอิทธิพลจากเบราว์เซอร์โฮสติ้ง


4

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

  • เครื่องเสมือนทำงานเหนือศีรษะรันไทม์มากขึ้นหรือไม่? ใช่
  • พวกเขากินหน่วยความจำในการทำงานมากขึ้นหรือไม่? ใช่
  • พวกเขามีต้นทุนการเริ่มต้นที่สูงขึ้น (การเริ่มต้นรันไทม์และคอมไพเลอร์ JIT) หรือไม่ ใช่
  • พวกเขาต้องการห้องสมุดขนาดใหญ่ติดตั้งหรือไม่? ใช่

และอื่น ๆ มันลำเอียงใช่;)

ด้วย C # และ Java คุณจะจ่ายราคาสำหรับสิ่งที่คุณได้รับ (การเข้ารหัสที่เร็วขึ้นการจัดการหน่วยความจำอัตโนมัติไลบรารีขนาดใหญ่และอื่น ๆ ) แต่คุณมีพื้นที่ไม่มากในการต่อรองเกี่ยวกับรายละเอียด: ใช้แพ็คเกจที่สมบูรณ์หรือไม่มีอะไรเลย

แม้ว่าภาษาเหล่านั้นจะสามารถเพิ่มประสิทธิภาพโค้ดบางส่วนเพื่อให้ทำงานได้เร็วกว่าโค้ดที่คอมไพล์แล้ว แต่วิธีการทั้งหมดก็ไม่มีประสิทธิภาพ (IMHO) ลองนึกภาพการขับรถทุกวัน 5 ไมล์ไปที่ทำงานของคุณด้วยรถบรรทุก! มันสบายรู้สึกดีคุณปลอดภัย (โซนย่นสุด ๆ ) และหลังจากที่คุณเหยียบแก๊สมาระยะหนึ่งมันจะเร็วเท่ากับรถมาตรฐาน! ทำไมเราทุกคนไม่มีรถบรรทุกขับไปทำงาน ;)

ใน C ++ คุณจะได้รับสิ่งที่คุณจ่ายไม่มากไม่น้อย

การอ้างถึง Bjarne Stroustrup: ข้อความลิงก์ "C ++ เป็นภาษาที่ฉันชอบเก็บขยะเพราะสร้างขยะน้อยมาก"


ฉันคิดว่าเขามีความคิดที่ดีเกี่ยวกับข้อเสียของมันเขายังกล่าวว่า: "C ทำให้ง่ายต่อการยิงด้วยเท้า C ++ ทำให้ยากขึ้น แต่เมื่อคุณทำมันจะทำให้ขาของคุณหลุดออกไปทั้งหมด";)
Frunsi

"พวกเขาต้องการไลบรารีขนาดใหญ่ที่ติดตั้ง" Java กำลังแก้ปัญหานี้ด้วยจิ๊กซอว์โครงการที่ฉันเชื่อ
toc777

"ใน C ++ คุณจะได้รับสิ่งที่คุณจ่ายไม่มากไม่น้อย" ตัวอย่างตัวนับ: ฉันเปรียบเทียบการใช้ทรี RB ใน OCaml และ C ++ (GNU GCC) ที่ใช้ข้อยกเว้นในการกระโดดออกจากการเรียกซ้ำแบบยาวหากมีการเพิ่มองค์ประกอบเพื่อนำชุดที่มีอยู่กลับมาใช้ใหม่ OCaml เร็วกว่า C ++ ถึง 6 เท่าเนื่องจากไม่ต้องเสียค่าใช้จ่ายในการตรวจหาตัวทำลายเนื่องจากสแต็กถูกคลายออก
JD

3
@ จอน: แต่ในบางช่วงเวลา (ในภายหลัง) ก็ต้องทำลายวัตถุอยู่ดี (อย่างน้อยก็ต้องปลดปล่อยความทรงจำ) และโปรดทราบว่าข้อยกเว้นมีไว้สำหรับกรณีพิเศษอย่างน้อยใน C ++ นั้นควรเคารพกฎ ข้อยกเว้น C ++ อาจหนักหนาสาหัสเมื่อเกิดข้อยกเว้นนั่นคือการแลกเปลี่ยน
Frunsi

@ จอน: อาจจะลองทำเกณฑ์มาตรฐานของคุณซ้ำด้วยtimesบนเชลล์ เพื่อให้ตรวจสอบโปรแกรมทั้งหมดไม่ใช่แค่ด้านเดียว ผลลัพธ์คล้ายกันหรือไม่?
Frunsi

3

โค้ดปฏิบัติการที่สร้างจากคอมไพเลอร์ Java หรือ C # ไม่ได้รับการตีความ - คอมไพล์เป็นโค้ดเนทีฟ "just in time" (JIT) ดังนั้นรหัสครั้งแรกในโปรแกรม Java / C # จะพบระหว่างการดำเนินการจึงมีค่าใช้จ่ายบางส่วนเนื่องจาก "รันไทม์คอมไพเลอร์" (หรือที่เรียกว่าคอมไพเลอร์ JIT) เปลี่ยนรหัสไบต์ (Java) หรือรหัส IL (C #) เป็นคำสั่งของเครื่องดั้งเดิม อย่างไรก็ตามในครั้งต่อไปที่พบโค้ดในขณะที่แอปพลิเคชันยังทำงานอยู่โค้ดเนทีฟจะดำเนินการทันที สิ่งนี้อธิบายว่าโปรแกรม Java / C # บางโปรแกรมดูเหมือนจะช้าในตอนแรก แต่จะทำงานได้ดีขึ้นเมื่อทำงานนานขึ้น ตัวอย่างที่ดีคือเว็บไซต์ ASP.Net ในครั้งแรกที่เข้าถึงเว็บไซต์อาจช้าลงเล็กน้อยเนื่องจากโค้ด C # ถูกคอมไพล์เป็นโค้ดเนทีฟโดยคอมไพเลอร์ JIT


3

คำตอบที่ดีเกี่ยวกับคำถามเฉพาะที่คุณถามที่นี่ ฉันอยากย้อนกลับไปดูภาพรวม

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

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

  • C # ของฉันอ่านและเข้าใจง่ายกว่า C ++ ฉันยังมีวิธีอื่น ๆ ในการโน้มน้าวตัวเองว่ารหัส C # ของฉันทำงานได้อย่างถูกต้อง นั่นหมายความว่าฉันสามารถเพิ่มประสิทธิภาพอัลกอริทึมของฉันโดยมีความเสี่ยงน้อยลงในการแนะนำจุดบกพร่อง (และผู้ใช้ไม่ชอบซอฟต์แวร์ที่ขัดข้องแม้ว่าจะทำได้เร็วก็ตาม!)

  • ฉันสามารถสร้างซอฟต์แวร์ของฉันใน C # ได้เร็วกว่าใน C ++ ซึ่งช่วยเพิ่มเวลาในการทำงานอย่างมีประสิทธิภาพและยังส่งมอบซอฟต์แวร์ได้ตรงเวลา

  • การเขียน UI ที่ดีใน C # ง่ายกว่า C ++ ดังนั้นฉันจึงมีแนวโน้มที่จะสามารถผลักดันงานไปยังพื้นหลังได้ในขณะที่ UI ยังคงตอบสนองหรือเพื่อให้ความคืบหน้าหรือได้ยินเสียง UI เมื่อโปรแกรมต้องปิดกั้นชั่วขณะ สิ่งนี้ไม่ได้ทำให้อะไรเร็วขึ้น แต่ทำให้ผู้ใช้มีความสุขกับการรอ

ทุกสิ่งที่ฉันพูดเกี่ยวกับ C # อาจเป็นจริงสำหรับ Java ฉันแค่ไม่มีประสบการณ์ที่จะพูดอย่างแน่นอน


3

หากคุณเป็นโปรแกรมเมอร์ Java / C # ที่เรียนรู้ C ++ คุณจะถูกล่อลวงให้คิดในแง่ของ Java / C # และแปลคำต่อคำเป็นไวยากรณ์ C ++ ในกรณีนี้คุณจะได้รับประโยชน์ที่กล่าวถึงก่อนหน้าของโค้ดเนทีฟเทียบกับการตีความ / JIT เพื่อให้ได้รับประสิทธิภาพสูงสุดใน C ++ เทียบกับ Java / C # คุณต้องเรียนรู้ที่จะคิดใน C ++ และออกแบบโค้ดโดยเฉพาะเพื่อใช้ประโยชน์จากจุดแข็งของ C ++

ในการถอดความEdsger Dijkstra : [ภาษาแรกของคุณ] ทำให้จิตใจขาดการฟื้นตัว
ในการถอดความJeff Atwood : คุณสามารถเขียน [ภาษาแรกของคุณ] ในภาษาใหม่ ๆ


1
ฉันสงสัยว่าคำพูดที่ว่า "คุณสามารถเขียนภาษาฟอร์แทรนในภาษาใดก็ได้" มาก่อนอาชีพของเจฟฟ์
David Thornley

3

การเพิ่มประสิทธิภาพ JIT ที่สำคัญที่สุดอย่างหนึ่งคือการฝังวิธี Java ยังสามารถใช้วิธีการเสมือนแบบอินไลน์ได้หากสามารถรับประกันความถูกต้องของรันไทม์ได้ การเพิ่มประสิทธิภาพแบบนี้มักจะไม่สามารถดำเนินการได้โดยคอมไพเลอร์สแตติกมาตรฐานเนื่องจากต้องการการวิเคราะห์ทั้งโปรแกรมซึ่งทำได้ยากเนื่องจากการคอมไพล์แยกต่างหาก (ในทางตรงกันข้าม JIT มีโปรแกรมทั้งหมดที่พร้อมใช้งาน) การแทรกวิธีการช่วยปรับปรุงการเพิ่มประสิทธิภาพอื่น ๆ ทำให้โค้ดบล็อกใหญ่ขึ้นเพื่อเพิ่มประสิทธิภาพ

การจัดสรรหน่วยความจำมาตรฐานใน Java / C # ก็เร็วขึ้นเช่นกันและการลดการจัดสรร (GC) ก็ไม่ช้าลงมากนัก แต่มีการกำหนดเพียงเล็กน้อยเท่านั้น


โปรดทราบว่าfreeและdeleteไม่สามารถกำหนดได้และ GC สามารถกำหนดได้โดยไม่จัดสรร
JD

3

ภาษาเครื่องเสมือนไม่น่าจะมีประสิทธิภาพดีกว่าภาษาที่คอมไพล์ แต่สามารถเข้าใกล้ได้มากพอที่จะไม่สำคัญสำหรับ (อย่างน้อย) เหตุผลต่อไปนี้ (ฉันกำลังพูดถึง Java ที่นี่เนื่องจากฉันไม่เคยทำ C #)

1 / Java Runtime Environment มักจะสามารถตรวจจับชิ้นส่วนของโค้ดที่รันบ่อยและทำการคอมไพล์แบบ Just-in-time (JIT) ของส่วนเหล่านั้นดังนั้นในอนาคตจะทำงานด้วยความเร็วในการคอมไพล์เต็มที่

2 / ส่วน Vast ของไลบรารี Java ถูกคอมไพล์ดังนั้นเมื่อคุณเรียกใช้ฟังก์ชันไลบรารีคุณกำลังเรียกใช้โค้ดที่คอมไพล์แล้วจะไม่ถูกตีความ คุณสามารถดูรหัส (ใน C) ได้โดยดาวน์โหลด OpenJDK

3 / เว้นแต่คุณจะทำการคำนวณจำนวนมากซึ่งส่วนใหญ่แล้วโปรแกรมของคุณกำลังทำงานอยู่มันกำลังรอการป้อนข้อมูลจากมนุษย์ที่พูดช้ามาก (ค่อนข้างพูด)

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

5 / ในกรณีที่เลวร้ายที่สุดโค้ดที่เน้นประสิทธิภาพสามารถแตกออกไปยังโมดูลที่คอมไพล์แล้วเรียกจาก Java (ดู JNI) เพื่อให้ทำงานด้วยความเร็วเต็มที่

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


1
Re item 2, "ส่วนที่ 2 / Vast ของไลบรารี Java ถูกคอมไพล์ดังนั้นเมื่อคุณเรียกใช้ฟังก์ชันไลบรารีคุณกำลังเรียกใช้โค้ดที่คอมไพล์แล้วไม่ได้ตีความ": คุณมีการอ้างอิงสำหรับสิ่งนั้นหรือไม่? หากเป็นไปตามที่คุณอธิบายจริงๆฉันคาดว่าจะพบกับโค้ดเนทีฟจากดีบักเกอร์ของฉันเป็นจำนวนมาก แต่ฉันไม่ทำ
cero

Re: cero Debuggers มักใช้เส้นทางที่มีประสิทธิภาพน้อยกว่า แต่แสดงออกได้ดีกว่าดังนั้นจึงไม่ใช่เครื่องหมายที่ดีสำหรับสิ่งที่เกี่ยวข้องกับประสิทธิภาพ
Guvante

2
มีประสิทธิภาพที่เพิ่มขึ้นอีกอย่างหนึ่งในไลบรารี HUGH นี้ - รหัสไลบรารีน่าจะเขียนได้ดีกว่าสิ่งที่โปรแกรมเมอร์จำนวนมากจะเขียนด้วยตัวเอง (ในเวลาที่ จำกัด และขาดความรู้เฉพาะทาง) และบน Java เนื่องจากหลายสาเหตุโปรแกรมเมอร์มักใช้ ห้องสมุด.
Liran Orevi

3

Orion Adrianให้ฉันสลับโพสต์ของคุณเพื่อดูว่าคำพูดของคุณไม่มีมูลความจริงเพราะสามารถพูดถึง C ++ ได้มากมายเช่นกัน และการบอกว่าคอมไพเลอร์ Java / C # ปรับแต่งฟังก์ชันที่ว่างเปล่าจะทำให้คุณดูเหมือนว่าคุณไม่ใช่ผู้เชี่ยวชาญด้านการเพิ่มประสิทธิภาพของฉันเพราะ a) ทำไมโปรแกรมจริงจึงมีฟังก์ชันว่างยกเว้นรหัสเดิมที่ไม่ดีจริงๆ b) นั่นไม่ใช่จริงๆ การเพิ่มประสิทธิภาพขอบดำและเลือดออก

นอกเหนือจากวลีนั้นคุณยังพูดจาโผงผางอย่างโจ่งแจ้งเกี่ยวกับตัวชี้ แต่วัตถุใน Java และ C # โดยทั่วไปไม่ได้ทำงานเหมือนตัวชี้ C ++ หรือไม่? ขอให้ไม่ทับซ้อนกัน? ขอให้พวกเขาไม่เป็นโมฆะ? C (และการใช้งาน C ++ ส่วนใหญ่) มีคีย์เวิร์ดที่ จำกัด ซึ่งทั้งคู่มีประเภทค่า C ++ มีการอ้างอิงถึงค่าพร้อมการรับประกันแบบไม่เป็นค่าว่าง Java และ C # เสนออะไร

>>>>>>>>>>

โดยทั่วไป C และ C ++ สามารถเร็วหรือเร็วกว่านั้นได้เนื่องจากคอมไพเลอร์ AOT ซึ่งเป็นคอมไพเลอร์ที่รวบรวมโค้ดของคุณก่อนการปรับใช้หนึ่งครั้งบนเซิร์ฟเวอร์สร้างคอร์ที่มีหน่วยความจำสูงจำนวนมากสามารถทำการปรับแต่งที่โปรแกรมคอมไพล์ C # ได้ ไม่สามารถทำได้เพราะมีเวลามากมายในการทำเช่นนั้น คอมไพเลอร์สามารถระบุได้ว่าเครื่องเป็น Intel หรือ AMD; Pentium 4, Core Solo หรือ Core Duo; หรือถ้ารองรับ SSE4 เป็นต้นและหากคอมไพเลอร์ของคุณไม่รองรับการจัดส่งรันไทม์คุณสามารถแก้ปัญหาได้ด้วยตัวเองโดยการปรับใช้ไบนารีเฉพาะจำนวนหนึ่ง

โดยทั่วไปโปรแกรม AC # จะคอมไพล์เมื่อรันเพื่อให้ทำงานได้ดีในทุกเครื่อง แต่ไม่ได้รับการปรับให้เหมาะสมที่สุดเท่าที่จะเป็นไปได้สำหรับการกำหนดค่าเดียว (เช่นโปรเซสเซอร์ชุดคำสั่งฮาร์ดแวร์อื่น ๆ ) และต้องใช้เวลาพอสมควร เป็นครั้งแรก คุณลักษณะต่างๆเช่นฟิชชันแบบวนซ้ำการกลับด้านแบบวนซ้ำการสร้างเวกเตอร์อัตโนมัติการเพิ่มประสิทธิภาพโปรแกรมทั้งหมดการขยายเทมเพลตการเสนอขายหุ้นและอื่น ๆ อีกมากมายนั้นยากมากที่จะแก้ไขได้ทั้งหมดและสมบูรณ์ในแบบที่ไม่รบกวนผู้ใช้

นอกจากนี้คุณลักษณะภาษาบางอย่างยังอนุญาตให้คอมไพเลอร์ใน C ++ หรือ C ตั้งสมมติฐานเกี่ยวกับโค้ดของคุณซึ่งอนุญาตให้เพิ่มประสิทธิภาพบางส่วนออกไปซึ่งไม่ปลอดภัยสำหรับคอมไพเลอร์ Java / C # เมื่อคุณไม่สามารถเข้าถึง id ประเภทเต็มของ generics หรือขั้นตอนการรับประกันโปรแกรมมีการเพิ่มประสิทธิภาพจำนวนมากที่ไม่ปลอดภัย

นอกจากนี้ C ++ และ C ยังทำการจัดสรรสแต็กจำนวนมากพร้อมกันด้วยการเพิ่มการลงทะเบียนเพียงครั้งเดียวซึ่งมีประสิทธิภาพมากกว่าการจัดสรร Javas และ C # สำหรับเลเยอร์ของสิ่งที่เป็นนามธรรมระหว่างตัวรวบรวมขยะและรหัสของคุณ

ตอนนี้ฉันไม่สามารถพูดกับ Java ในจุดต่อไปนี้ได้ แต่ฉันรู้ว่าตัวอย่างเช่นคอมไพเลอร์ C ++ จะลบเมธอดและการเรียกเมธอดเมื่อรู้ว่าเนื้อหาของเมธอดว่างเปล่ามันจะกำจัดนิพจน์ย่อยทั่วไปอาจลองแล้วลองอีกครั้ง เพื่อค้นหาการใช้งานรีจิสเตอร์ที่เหมาะสมที่สุดจะไม่บังคับใช้การตรวจสอบขอบเขตมันจะกำหนดลูปและลูปด้านในโดยอัตโนมัติและจะกลับด้านในเป็นด้านนอกโดยจะย้ายเงื่อนไขออกจากลูปโดยจะแยกและไม่แยกลูป มันจะขยาย std :: vector ให้เป็นอาร์เรย์ค่าโสหุ้ยศูนย์เนทีฟตามที่คุณทำในทาง C มันจะทำการเพิ่มประสิทธิภาพระหว่างขั้นตอน จะสร้างค่าส่งกลับโดยตรงที่ไซต์ผู้โทร มันจะพับและเผยแพร่นิพจน์ จะเรียงลำดับข้อมูลใหม่ในลักษณะที่เป็นมิตรกับแคช มันจะกระโดดเธรด ช่วยให้คุณสามารถเขียน compile time ray tracers โดยมีค่าโสหุ้ยรันไทม์เป็นศูนย์ มันจะทำการเพิ่มประสิทธิภาพตามกราฟที่มีราคาแพงมาก มันจะทำการลดความแรงหากมันจะแทนที่โค้ดบางตัวด้วยโค้ดที่ไม่เท่ากันโดยสิ้นเชิง แต่มีความหมายเชิงวากยสัมพันธ์ ("xor foo, foo" แบบเก่าเป็นเพียงวิธีที่ง่ายที่สุดแม้ว่าการเพิ่มประสิทธิภาพที่ล้าสมัยในประเภทดังกล่าว) หากคุณกรุณาถามคุณอาจละเว้นมาตรฐานจุดลอยตัวของ IEEE และเปิดใช้งานการปรับให้เหมาะสมมากยิ่งขึ้นเช่นการสั่งซื้อตัวดำเนินการจุดลอยตัวใหม่ หลังจากที่ได้รับการนวดและบีบรหัสของคุณแล้วระบบอาจทำซ้ำขั้นตอนทั้งหมดเพราะบ่อยครั้งการเพิ่มประสิทธิภาพบางอย่างจะวางรากฐานสำหรับการเพิ่มประสิทธิภาพบางอย่าง นอกจากนี้ยังอาจลองอีกครั้งโดยใช้พารามิเตอร์แบบสับและดูว่าตัวแปรอื่น ๆ ให้คะแนนอย่างไรในการจัดอันดับภายใน และจะใช้ตรรกะแบบนี้ตลอดโค้ดของคุณ มันแทนที่รหัสบางตัวด้วยรหัสที่ไม่เท่ากันทางวากยสัมพันธ์โดยสิ้นเชิง แต่มีความหมายเทียบเท่ากัน ("xor foo, foo" แบบเก่าเป็นเพียงวิธีที่ง่ายที่สุดแม้ว่าจะล้าสมัยการเพิ่มประสิทธิภาพประเภทนี้ก็ตาม) หากคุณกรุณาถามคุณอาจละเว้นมาตรฐานจุดลอยตัวของ IEEE และเปิดใช้งานการปรับให้เหมาะสมมากยิ่งขึ้นเช่นการสั่งซื้อตัวดำเนินการจุดลอยตัวใหม่ หลังจากที่ได้รับการนวดและบีบรหัสของคุณแล้วระบบอาจทำซ้ำขั้นตอนทั้งหมดเพราะบ่อยครั้งการเพิ่มประสิทธิภาพบางอย่างจะวางรากฐานสำหรับการเพิ่มประสิทธิภาพบางอย่าง นอกจากนี้ยังอาจลองอีกครั้งโดยใช้พารามิเตอร์แบบสับและดูว่าตัวแปรอื่น ๆ ให้คะแนนอย่างไรในการจัดอันดับภายใน และจะใช้ตรรกะแบบนี้ตลอดโค้ดของคุณ มันแทนที่รหัสบางตัวด้วยรหัสที่ไม่เท่ากันทางวากยสัมพันธ์โดยสิ้นเชิง แต่มีความหมายเทียบเท่ากัน ("xor foo, foo" แบบเก่าเป็นเพียงวิธีที่ง่ายที่สุดแม้ว่าจะล้าสมัยการเพิ่มประสิทธิภาพประเภทนี้ก็ตาม) หากคุณกรุณาถามคุณอาจละเว้นมาตรฐานจุดลอยตัวของ IEEE และเปิดใช้งานการปรับให้เหมาะสมมากยิ่งขึ้นเช่นการสั่งซื้อตัวดำเนินการจุดลอยตัวใหม่ หลังจากที่ได้รับการนวดและบีบรหัสของคุณแล้วระบบอาจทำซ้ำขั้นตอนทั้งหมดเพราะบ่อยครั้งการเพิ่มประสิทธิภาพบางอย่างจะวางรากฐานสำหรับการเพิ่มประสิทธิภาพบางอย่าง นอกจากนี้ยังอาจลองอีกครั้งโดยใช้พารามิเตอร์แบบสับและดูว่าตัวแปรอื่น ๆ ให้คะแนนอย่างไรในการจัดอันดับภายใน และจะใช้ตรรกะแบบนี้ตลอดโค้ดของคุณ หากคุณกรุณาถามคุณอาจละเว้นมาตรฐานจุดลอยตัวของ IEEE และเปิดใช้งานการปรับให้เหมาะสมมากยิ่งขึ้นเช่นการสั่งซื้อตัวดำเนินการจุดลอยตัวใหม่ หลังจากที่ได้รับการนวดและบีบรหัสของคุณแล้วระบบอาจทำซ้ำขั้นตอนทั้งหมดเพราะบ่อยครั้งการเพิ่มประสิทธิภาพบางอย่างจะวางรากฐานสำหรับการเพิ่มประสิทธิภาพบางอย่าง นอกจากนี้ยังอาจลองอีกครั้งโดยใช้พารามิเตอร์แบบสับและดูว่าตัวแปรอื่น ๆ ให้คะแนนอย่างไรในการจัดอันดับภายใน และจะใช้ตรรกะแบบนี้ตลอดโค้ดของคุณ หากคุณกรุณาถามคุณอาจละเว้นมาตรฐานจุดลอยตัวของ IEEE และเปิดใช้งานการปรับให้เหมาะสมมากยิ่งขึ้นเช่นการสั่งซื้อตัวดำเนินการจุดลอยตัวใหม่ หลังจากที่ได้รับการนวดและบีบรหัสของคุณแล้วระบบอาจทำซ้ำขั้นตอนทั้งหมดเพราะบ่อยครั้งการเพิ่มประสิทธิภาพบางอย่างจะวางรากฐานสำหรับการเพิ่มประสิทธิภาพบางอย่าง นอกจากนี้ยังอาจลองอีกครั้งโดยใช้พารามิเตอร์แบบสับและดูว่าตัวแปรอื่น ๆ ให้คะแนนอย่างไรในการจัดอันดับภายใน และจะใช้ตรรกะแบบนี้ตลอดโค้ดของคุณ นอกจากนี้ยังอาจลองอีกครั้งโดยใช้พารามิเตอร์แบบสับและดูว่าตัวแปรอื่น ๆ ให้คะแนนอย่างไรในการจัดอันดับภายใน และจะใช้ตรรกะแบบนี้ตลอดโค้ดของคุณ นอกจากนี้ยังอาจลองอีกครั้งโดยใช้พารามิเตอร์แบบสับและดูว่าตัวแปรอื่น ๆ ให้คะแนนอย่างไรในการจัดอันดับภายใน และจะใช้ตรรกะแบบนี้ตลอดโค้ดของคุณ

ดังที่คุณเห็นมีหลายสาเหตุที่การใช้งาน C ++ หรือ C บางอย่างจะเร็วขึ้น

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

ขึ้นอยู่กับสิ่งที่คุณกำลังเขียนฉันจะไปกับอย่างใดอย่างหนึ่ง แต่ถ้าคุณกำลังเขียนบางอย่างที่ไม่ได้ขึ้นอยู่กับฮาร์ดแวร์ (ไดรเวอร์วิดีโอเกม ฯลฯ ) ฉันจะไม่กังวลเกี่ยวกับประสิทธิภาพของ C # (พูดถึง Java ไม่ได้อีกแล้ว) มันจะทำได้ดี

<<<<<<<<<<

โดยทั่วไปข้อโต้แย้งทั่วไปบางอย่างอาจฟังดูดีในบางโพสต์ แต่โดยทั่วไปแล้วไม่น่าเชื่อถืออย่างแน่นอน

Anyways เพื่อสร้างสันติภาพ: ทอทเป็นสิ่งที่ดีเป็นJIT คำตอบเดียวที่ถูกต้องสามารถ: ขึ้นอยู่กับ และคนฉลาดตัวจริงรู้ว่าคุณสามารถใช้สิ่งที่ดีที่สุดจากทั้งสองโลกได้


2

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

อย่างไรก็ตามอัตราต่อรองที่เกิดขึ้นจริงนั้นค่อนข้างต่ำเว้นแต่ Java อาจมีไลบรารีที่เขียนได้ดีมากและคุณมีไลบรารี C ++ ที่เขียนไม่ดี


ฉันยังเชื่อว่ามีน้ำหนักภาษาที่แน่นอนเช่นกันเมื่อทำงานในระดับที่ต่ำกว่าโดยมีนามธรรมน้อยลงคุณจะพัฒนาโปรแกรมได้เร็วขึ้น สิ่งนี้ไม่เกี่ยวข้องกับประเด็นเกี่ยวกับการดำเนินการ bytecode เอง
Brian R.Bondy

2

จริงๆแล้ว C # ไม่ได้ทำงานในเครื่องเสมือนจริงเช่น Java IL ถูกรวบรวมเป็นภาษาแอสเซมบลีซึ่งเป็นรหัสดั้งเดิมทั้งหมดและทำงานด้วยความเร็วเดียวกันกับโค้ดเนทีฟ คุณสามารถ Pre-JIT แอปพลิเคชัน. NET ซึ่งจะลบต้นทุน JIT ออกทั้งหมดจากนั้นคุณจะรันโค้ดเนทีฟทั้งหมด

การชะลอตัวด้วย. NET จะไม่เกิดขึ้นเนื่องจากรหัส. NET ทำงานช้ากว่า แต่เป็นเพราะมันทำงานอยู่เบื้องหลังมากขึ้นในการทำสิ่งต่างๆเช่นการรวบรวมขยะตรวจสอบการอ้างอิงจัดเก็บสแต็กเฟรมที่สมบูรณ์ ฯลฯ สิ่งนี้ค่อนข้างมีประสิทธิภาพและเป็นประโยชน์เมื่อ การสร้างแอปพลิเคชัน แต่ยังมีค่าใช้จ่าย โปรดทราบว่าคุณสามารถทำสิ่งเหล่านี้ทั้งหมดในโปรแกรม C ++ ได้เช่นกัน (ฟังก์ชัน. NET หลักส่วนใหญ่เป็นรหัส. NET ซึ่งคุณสามารถดูได้ใน ROTOR) อย่างไรก็ตามหากคุณเขียนฟังก์ชันเดียวกันด้วยมือคุณอาจจะจบลงด้วยโปรแกรมที่ช้าลงมากเนื่องจากรันไทม์. NET ได้รับการปรับให้เหมาะสมและได้รับการปรับแต่งอย่างละเอียด

กล่าวได้ว่าจุดแข็งอย่างหนึ่งของโค้ดที่มีการจัดการคือสามารถตรวจสอบได้อย่างสมบูรณ์กล่าวคือ คุณสามารถตรวจสอบได้ว่ารหัสจะไม่เข้าถึงหน่วยความจำของกระบวนการอื่นหรือทำการยกเลิกการใช้งานก่อนที่คุณจะดำเนินการ Microsoft มีต้นแบบการวิจัยของระบบปฏิบัติการที่มีการจัดการเต็มรูปแบบซึ่งแสดงให้เห็นอย่างน่าประหลาดใจว่าสภาพแวดล้อมที่มีการจัดการ 100% สามารถทำงานได้เร็วกว่าระบบปฏิบัติการสมัยใหม่อย่างมากโดยใช้ประโยชน์จากการตรวจสอบนี้เพื่อปิดคุณลักษณะด้านความปลอดภัยที่โปรแกรมที่จัดการไม่ต้องการอีกต่อไป (เรากำลังพูดถึง 10x ในบางกรณี) SE radio มีตอนดีๆที่พูดถึงโครงการนี้


1

ในบางกรณีโค้ดที่มีการจัดการอาจเร็วกว่าโค้ดเนทีฟ ตัวอย่างเช่นอัลกอริธึมการรวบรวมขยะ "mark-and-Sweep" อนุญาตให้สภาพแวดล้อมเช่น JRE หรือ CLR ปลดปล่อยออบเจ็กต์ที่มีอายุสั้น (โดยปกติ) จำนวนมากในการส่งครั้งเดียวโดยที่วัตถุฮีป C / C ++ ส่วนใหญ่จะเป็นอิสระ เวลา.

จากวิกิพีเดีย :

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

ที่กล่าวว่าฉันได้เขียน C # และ C ++ จำนวนมากและฉันใช้เกณฑ์มาตรฐานจำนวนมาก จากประสบการณ์ของผม, C ++ เป็นจำนวนมากได้เร็วกว่า C # ในสองวิธี (1) ถ้าคุณใช้รหัสบางอย่างที่คุณเขียนใน C #, พอร์ตเพื่อให้ c ++ รหัสพื้นเมืองมีแนวโน้มที่จะเร็ว เร็วขึ้นเท่าไร มันแตกต่างกันมาก แต่ไม่ใช่เรื่องแปลกที่จะเห็นการปรับปรุงความเร็ว 100% (2) ในบางกรณีการเก็บขยะสามารถอย่างหนาแน่นชะลอตัวลงเป็นโปรแกรมการจัดการ NET CLR ทำงานได้อย่างยอดเยี่ยมด้วยกองขนาดใหญ่ (เช่น> 2GB) และสามารถใช้เวลาส่วนใหญ่ใน GC ได้แม้ในแอปพลิเคชันที่มีช่วงชีวิตระดับกลางเพียงเล็กน้อยหรือไม่มีเลยก็ตาม

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


1
ปัญหาคือสำหรับกระบวนการที่ทำงานเป็นเวลานานเช่นเว็บเซิร์ฟเวอร์หน่วยความจำของคุณเมื่อเวลาผ่านไปจะกระจัดกระจาย (ในโปรแกรมที่เขียนด้วย C ++) ซึ่งคุณจะต้องใช้สิ่งที่คล้ายกับการรวบรวมขยะ (หรือรีสตาร์ททุกครั้งดู IIS )
Tony BenBrahim

3
ฉันไม่ได้สังเกตว่าในโปรแกรม Unix ขนาดใหญ่ที่ตั้งใจจะทำงานตลอดไป พวกเขามักจะเขียนด้วยภาษา C ซึ่งแย่กว่าสำหรับการจัดการหน่วยความจำมากกว่า C ++
David Thornley

แน่นอนคำถามคือเรากำลังเปรียบเทียบการใช้งานโปรแกรมในโค้ดที่มีการจัดการเทียบกับโค้ดที่ไม่มีการจัดการหรือประสิทธิภาพสูงสุดตามทฤษฎีของภาษา เห็นได้ชัดว่าโค้ดที่ไม่มีการจัดการอย่างน้อยก็เร็วพอ ๆ กับที่มีการจัดการในกรณีที่เลวร้ายที่สุดคุณสามารถเขียนโปรแกรมที่ไม่มีการจัดการซึ่งทำสิ่งเดียวกับโค้ดที่มีการจัดการ! แต่ปัญหาด้านประสิทธิภาพส่วนใหญ่เกิดจากอัลกอริทึมไม่ใช่ไมโคร นอกจากนี้คุณไม่ได้เพิ่มประสิทธิภาพโค้ดที่มีการจัดการและไม่มีการจัดการด้วยวิธีเดียวกันดังนั้น "C ++ ใน C #" มักจะทำงานได้ไม่ดี
kyoryu

2
ใน C / C ++ คุณสามารถจัดสรรออบเจ็กต์ที่มีอายุสั้นบนสแต็กและคุณจะทำตามความเหมาะสม ในรหัสที่มีการจัดการคุณไม่สามารถทำได้คุณไม่มีทางเลือก นอกจากนี้ใน C / C ++ คุณสามารถจัดสรรรายการวัตถุในพื้นที่ที่ต่อเนื่องกัน (Foo ใหม่ [100]) ในโค้ดที่มีการจัดการคุณไม่สามารถทำได้ ดังนั้นการเปรียบเทียบของคุณจึงไม่ถูกต้อง พลังแห่งการเลือกนี้สร้างภาระให้กับนักพัฒนา แต่ด้วยวิธีนี้พวกเขาเรียนรู้ที่จะรู้จักโลกที่พวกเขาอาศัยอยู่ (ความทรงจำ ...... )
Frunsi

@frunsi: "ใน C / C ++ คุณสามารถจัดสรรรายการวัตถุในพื้นที่ต่อเนื่องกัน (Foo [100] ใหม่) ในโค้ดที่มีการจัดการคุณไม่สามารถ" นั่นไม่ถูกต้อง ประเภทค่าในเครื่องจะได้รับการจัดสรรกองซ้อนและคุณยังสามารถจัดสรรอาร์เรย์ของพวกเขาใน C # มีแม้แต่ระบบการผลิตที่เขียนด้วย C # ซึ่งไม่มีการจัดสรรอย่างสมบูรณ์ในสภาวะคงที่
JD


1

ที่จริงแล้ว JVM HotSpot ของ Sun ใช้การดำเนินการ "โหมดผสม" มันตีความรหัส bytecode ของเมธอดจนกว่าจะกำหนด (โดยปกติจะผ่านตัวนับของการเรียงลำดับบางอย่าง) ว่าบล็อกโค้ดเฉพาะ (วิธีการลูปบล็อกการลองจับ ฯลฯ ) จะถูกเรียกใช้งานเป็นจำนวนมากจากนั้น JIT จะรวบรวมมัน เวลาที่ต้องใช้ในการคอมไพล์ JIT เมธอดมักใช้เวลานานกว่าที่จะตีความเมธอดหากเป็นเมธอดที่ไม่ค่อยมีการรัน โดยปกติประสิทธิภาพจะสูงกว่าสำหรับ "โหมดผสม" เนื่องจาก JVM ไม่เสียเวลา JITing โค้ดที่แทบจะไม่เคยรัน C # และ. NET ไม่ทำเช่นนี้ .NET JIT ทุกอย่างที่เสียเวลาบ่อยครั้ง


1

ไปอ่านเกี่ยวกับDynamoของ HP Labs ซึ่งเป็นล่ามสำหรับ PA-8000 ที่ทำงานบน PA-8000 และมักเรียกใช้โปรแกรมได้เร็วกว่าที่ทำโดยกำเนิด แล้วมันจะไม่น่าแปลกใจเลย!

อย่าคิดว่าเป็น "ขั้นตอนกลาง" - การเรียกใช้โปรแกรมเกี่ยวข้องกับขั้นตอนอื่น ๆ มากมายแล้วไม่ว่าจะเป็นภาษาใดก็ตาม

มักจะลงมาที่:

  • โปรแกรมมีฮอตสปอตดังนั้นแม้ว่าคุณจะทำงานช้าลง 95% ของเนื้อโค้ดที่คุณต้องรันคุณก็ยังสามารถแข่งขันด้านประสิทธิภาพได้หากคุณเร็วขึ้นที่ 5%

  • HLL รู้เกี่ยวกับเจตนาของคุณมากกว่า LLL เช่น C / C ++ และสามารถสร้างโค้ดที่เหมาะสมได้มากขึ้น (OCaml มีมากกว่าและในทางปฏิบัติมักจะเร็วกว่า)

  • คอมไพเลอร์ JIT มีข้อมูลมากมายที่คอมไพเลอร์สแตติกไม่ชอบ (เช่นข้อมูลจริงที่คุณมีในครั้งนี้)

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

สรุปแล้ว C / C ++ เป็นภาษาที่ค่อนข้างน่ากลัวสำหรับประสิทธิภาพ: มีข้อมูลค่อนข้างน้อยเกี่ยวกับประเภทข้อมูลของคุณไม่มีข้อมูลเกี่ยวกับข้อมูลของคุณและไม่มีรันไทม์แบบไดนามิกที่จะอนุญาตให้มีการเพิ่มประสิทธิภาพรันไทม์ได้มากนัก


1

คุณอาจได้รับการระเบิดสั้น ๆ เมื่อ Java หรือ CLR เร็วกว่า C ++ แต่โดยรวมแล้วประสิทธิภาพจะแย่ลงสำหรับอายุการใช้งานของแอปพลิเคชัน: ดู www.codeproject.com/KB/dotnet/RuntimePerformance.aspx สำหรับผลลัพธ์บางอย่าง



1

ความเข้าใจของฉันคือ C / C ++ สร้างโค้ดเนทีฟเพื่อรันบนสถาปัตยกรรมเครื่องเฉพาะ ในทางกลับกันภาษาเช่น Java และ C # ทำงานบนเครื่องเสมือนซึ่งแยกสถาปัตยกรรมดั้งเดิมออกไป ดูเหมือนจะเป็นไปไม่ได้ที่ Java หรือ C # จะจับคู่ความเร็วของ C ++ เนื่องจากขั้นตอนกลางนี้อย่างไรก็ตามฉันได้รับแจ้งว่าคอมไพเลอร์ล่าสุด ("ฮอตสปอต") สามารถบรรลุความเร็วนี้หรือสูงกว่านั้นได้

นั่นเป็นเรื่องที่ไร้เหตุผล การใช้ตัวแทนระดับกลางไม่ได้ทำให้ประสิทธิภาพลดลงโดยเนื้อแท้ ตัวอย่างเช่น llvm-gcc คอมไพล์ C และ C ++ ผ่าน LLVM IR (ซึ่งเป็นเครื่องลงทะเบียนเสมือนไม่มีที่สิ้นสุด) ไปยังโค้ดเนทีฟและได้ประสิทธิภาพที่ยอดเยี่ยม (มักจะเอาชนะ GCC)

บางทีนี่อาจเป็นคำถามเกี่ยวกับคอมไพเลอร์มากกว่าคำถามด้านภาษา แต่ใครก็ได้สามารถอธิบายเป็นภาษาอังกฤษแบบธรรมดาได้ว่าภาษาเครื่องเสมือนเหล่านี้จะทำงานได้ดีกว่าภาษาแม่หรือไม่

นี่คือตัวอย่างบางส่วน:

  • เครื่องเสมือนที่มีการคอมไพล์ JIT ช่วยอำนวยความสะดวกในการสร้างโค้ดรันไทม์ (เช่นSystem.Reflection.Emitบน. NET) ดังนั้นคุณสามารถรวบรวมโค้ดที่สร้างขึ้นได้ทันทีในภาษาเช่น C # และ F # แต่ต้องหันไปใช้การเขียนล่ามที่ค่อนข้างช้าใน C หรือ C ++ ตัวอย่างเช่นเพื่อใช้นิพจน์ทั่วไป

  • ส่วนต่างๆของเครื่องเสมือน (เช่นตัวกั้นการเขียนและตัวจัดสรร) มักจะเขียนด้วยแอสเซมเบลอร์ด้วยมือเนื่องจาก C และ C ++ ไม่สร้างโค้ดที่เร็วพอ หากโปรแกรมเน้นส่วนเหล่านี้ของระบบอาจมีประสิทธิภาพดีกว่าสิ่งที่สามารถเขียนด้วย C หรือ C ++ ได้

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

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

การประมวลผลโค้ดจะเสร็จสิ้นในเวลาคอมไพล์ ...

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

... การเล่นกับประเภทเสร็จสิ้นในเวลาคอมไพล์ ... การเทียบเท่าใน Java หรือ C # นั้นเจ็บปวดที่สุดในการเขียนและจะช้ากว่าและได้รับการแก้ไขเมื่อรันไทม์แม้ว่าจะทราบประเภทในเวลาคอมไพล์ก็ตาม

ใน C # นั่นเป็นเพียงความจริงของชนิดการอ้างอิงและไม่เป็นความจริงสำหรับชนิดค่า

ไม่ว่าการเพิ่มประสิทธิภาพ JIT จะไม่มีอะไรเร็วเท่ากับการเข้าถึงตัวชี้โดยตรงไปยังหน่วยความจำ ... หากคุณมีข้อมูลที่ต่อเนื่องกันในหน่วยความจำการเข้าถึงผ่านตัวชี้ C ++ (เช่นตัวชี้ C ... ขอให้ Caesar ครบกำหนด) จะเร็วขึ้นหลายเท่า กว่าใน Java / C #

ผู้คนสังเกตว่าJava เอาชนะ C ++ ในการทดสอบ SOR จากเกณฑ์มาตรฐาน SciMark2อย่างแม่นยำเนื่องจากตัวชี้ขัดขวางการปรับแต่งที่เกี่ยวข้องกับนามแฝง

นอกจากนี้ที่น่าสังเกตว่า. NET พิมพ์ความเชี่ยวชาญเฉพาะทางของยาสามัญข้ามไลบรารีที่เชื่อมโยงแบบไดนามิกหลังจากการเชื่อมโยงในขณะที่ C ++ ไม่สามารถทำได้เนื่องจากเทมเพลตต้องได้รับการแก้ไขก่อนการเชื่อมโยง และเห็นได้ชัดว่า generics ที่ได้เปรียบใหญ่มีมากกว่าเทมเพลตคือข้อความแสดงข้อผิดพลาดที่เข้าใจได้


0

นอกเหนือจากสิ่งที่คนอื่นพูดจากความเข้าใจของฉัน. NET และ Java ดีกว่าในการจัดสรรหน่วยความจำ เช่นพวกเขาสามารถกระชับหน่วยความจำเมื่อมันแยกส่วนในขณะที่ C ++ ทำไม่ได้ (โดยกำเนิด แต่สามารถทำได้ถ้าคุณใช้เครื่องเก็บขยะที่ชาญฉลาด)


หรือถ้าคุณใช้ตัวจัดสรร C ++ ที่ดีกว่าและ / หรือกลุ่มวัตถุ สิ่งนี้ยังห่างไกลจากเวทมนตร์จากมุมมอง C ++ และอาจทำให้ "การจัดสรรฮีป" กลายเป็นการจัดสรรกองซ้อนได้อย่างรวดเร็ว
paercebal

หากคุณจัดสรรทุกอย่างบนฮีปเสมอดังนั้น. NET และ Java อาจทำงานได้ดีกว่า C / C ++ แต่คุณจะไม่ทำใน C / C ++
Frunsi

0

สำหรับทุกสิ่งที่ต้องการความเร็วสูง JVM เพียงแค่เรียกการใช้งาน C ++ ดังนั้นจึงเป็นคำถามที่มากกว่าว่า libs ของพวกเขาดีแค่ไหน JVM นั้นดีแค่ไหนสำหรับสิ่งที่เกี่ยวข้องกับระบบปฏิบัติการส่วนใหญ่ การรวบรวมขยะจะลดหน่วยความจำของคุณลงครึ่งหนึ่ง แต่การใช้คุณลักษณะ STL และ Boost ที่น่าสนใจบางอย่างจะให้ผลเช่นเดียวกัน แต่อาจมีข้อผิดพลาดหลายเท่า

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

อย่างไรก็ตามประโยชน์ของ C ++ คือช่วยให้คุณปรับแต่งตัวเองให้เหมาะสมไม่เช่นนั้นคุณจะติดขัดกับสิ่งที่คอมไพเลอร์ / jvm ทำ หากคุณสร้างคอนเทนเนอร์ของคุณเองให้เขียนการจัดการหน่วยความจำของคุณเองที่จัดแนวใช้ SIMD และวางลงในแอสเซมบลีที่นี่และที่นั่นคุณสามารถเพิ่มความเร็วได้อย่างน้อย 2x-4x เท่าของสิ่งที่คอมไพเลอร์ C ++ ส่วนใหญ่จะทำด้วยตัวเอง สำหรับการดำเนินการบางอย่าง 16x-32x นั่นคือการใช้อัลกอริทึมเดียวกันหากคุณใช้อัลกอริทึมที่ดีกว่าและขนานกันการเพิ่มขึ้นอาจเป็นเรื่องที่น่าทึ่งบางครั้งเร็วกว่าที่ใช้กันทั่วไปหลายพันเท่า


0

ฉันมองจากจุดที่แตกต่างกันเล็กน้อย

  1. ด้วยเวลาและทรัพยากรที่ไม่มีที่สิ้นสุดโค้ดที่มีการจัดการหรือไม่มีการจัดการจะเร็วขึ้นหรือไม่? เห็นได้ชัดว่าคำตอบก็คือโค้ดที่ไม่มีการจัดการอย่างน้อยก็สามารถผูกโค้ดที่มีการจัดการในแง่มุมนี้ได้เสมอเช่นในกรณีที่เลวร้ายที่สุดคุณเพียงแค่ฮาร์ดโค้ดโซลูชันโค้ดที่มีการจัดการ
  2. หากคุณใช้โปรแกรมในภาษาหนึ่งและแปลเป็นภาษาอื่นโดยตรงโปรแกรมจะทำงานได้แย่ลงมากแค่ไหน? อาจมากสำหรับสองภาษาใด ๆ ภาษาส่วนใหญ่ต้องการการเพิ่มประสิทธิภาพที่แตกต่างกันและมี gotcha ที่แตกต่างกัน ประสิทธิภาพระดับจุลภาคมักเป็นเรื่องเกี่ยวกับการทราบรายละเอียดเหล่านี้
  3. ด้วยเวลาและทรัพยากรที่ จำกัด ภาษาใดในสองภาษาที่จะให้ผลลัพธ์ที่ดีกว่า นี่เป็นคำถามที่น่าสนใจที่สุดเนื่องจากในขณะที่ภาษาที่มีการจัดการอาจสร้างรหัสที่ช้าลงเล็กน้อย (เนื่องจากโปรแกรมที่เขียนขึ้นอย่างสมเหตุสมผลสำหรับภาษานั้น) เวอร์ชันนั้นจะเสร็จเร็วกว่าทำให้ใช้เวลาในการปรับให้เหมาะสมมากขึ้น

0

คำตอบสั้น ๆ : ด้วยงบประมาณที่แน่นอนคุณจะได้แอปพลิเคชัน java ที่มีประสิทธิภาพดีกว่าแอปพลิเคชัน C ++ (ข้อควรพิจารณาเกี่ยวกับ ROI) นอกจากนี้แพลตฟอร์ม Java ยังมีโปรไฟล์ที่เหมาะสมกว่าซึ่งจะช่วยให้คุณระบุฮอตสปอตของคุณได้เร็วขึ้น

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