คุณรู้สึกว่ามีการแลกเปลี่ยนระหว่างการเขียนโค้ด "ดี" ของโอเรียนท์กับการเขียนโค้ดเวลาแฝงที่ต่ำมาก ๆ หรือไม่? ตัวอย่างเช่นการหลีกเลี่ยงฟังก์ชั่นเสมือนจริงใน C ++ / ค่าโสหุ้ยของ polymorphism เป็นต้นการเขียนโค้ดที่ดูน่ารังเกียจ แต่มันเร็วมากหรือเปล่า?
ผมทำงานในสาขาซึ่งเป็นบิตเน้นมากขึ้นในการส่งผ่านกว่าแฝง แต่มันมากประสิทธิภาพการทำงานที่สำคัญและผมว่า"sorta"
แต่ปัญหาคือคนจำนวนมากได้รับแนวคิดเรื่องการแสดงผิดอย่างสิ้นเชิง สามเณรมักจะผิดพลาดทุกอย่างและโมเดลเชิงแนวคิดทั้งหมดของ "ต้นทุนการคำนวณ" จำเป็นต้องได้รับการทำงานซ้ำโดยมีความซับซ้อนของอัลกอริทึมเพียงอย่างเดียวเกี่ยวกับสิ่งเดียวที่พวกเขาทำได้ถูกต้อง สื่อกลางเข้าใจผิดหลายอย่าง ผู้เชี่ยวชาญเข้าใจผิด
การวัดด้วยเครื่องมือที่แม่นยำที่สามารถให้การวัดเช่นการพลาดแคชและการคาดคะเนผิดพลาดของสาขาคือสิ่งที่ทำให้ทุกคนในทุกระดับของความเชี่ยวชาญในสาขาในการตรวจสอบ
วัดยังเป็นสิ่งที่ชี้ให้เห็นสิ่งที่ไม่ต้องเพิ่มประสิทธิภาพ ผู้เชี่ยวชาญมักใช้เวลาในการปรับให้เหมาะสมน้อยกว่าสามเณรเนื่องจากพวกเขากำลังปรับฮอตสปอตที่วัดจริงและไม่พยายามเพิ่มประสิทธิภาพแทงป่าในที่มืดโดยดูจากลางสังหรณ์ว่าอะไรจะช้า (ซึ่งในรูปแบบสุดขีด เกี่ยวกับบรรทัดอื่น ๆ ใน codebase)
การออกแบบเพื่อประสิทธิภาพ
นอกเหนือจากนั้นกุญแจสู่การออกแบบเพื่อประสิทธิภาพมาจากส่วนการออกแบบเช่นเดียวกับการออกแบบอินเตอร์เฟส หนึ่งในปัญหาที่ไม่มีประสบการณ์คือมีแนวโน้มที่จะมีการเปลี่ยนแปลงในช่วงแรกของการใช้งานแบบสัมบูรณ์เช่นต้นทุนของการเรียกฟังก์ชั่นทางอ้อมในบริบททั่วไปบางอย่างเช่นค่าใช้จ่าย (ซึ่งเป็นที่เข้าใจได้ดีกว่า ของมุมมองมากกว่ามุมมองการแตกแขนง) เป็นเหตุผลที่หลีกเลี่ยงมันตลอดทั้ง codebase
ค่าใช้จ่ายที่เป็นญาติ ในขณะที่มีค่าใช้จ่ายในการเรียกใช้ฟังก์ชันทางอ้อมเช่นค่าใช้จ่ายทั้งหมดจะสัมพันธ์กัน หากคุณจ่ายค่าใช้จ่ายเพียงครั้งเดียวเพื่อเรียกใช้ฟังก์ชันที่วนซ้ำไปมาหลายล้านองค์ประกอบการกังวลเกี่ยวกับค่าใช้จ่ายนี้ก็เหมือนกับการใช้เวลาหลายชั่วโมงในการซื้อเพนนีสำหรับการซื้อผลิตภัณฑ์หนึ่งพันล้านดอลลาร์เท่านั้นเพื่อสรุปว่าจะไม่ซื้อผลิตภัณฑ์นั้น ราคาแพงเกินไป
การออกแบบส่วนต่อประสานที่หยาบ
ด้านการออกแบบส่วนต่อประสานของประสิทธิภาพมักจะค้นหาก่อนหน้านี้เพื่อผลักดันค่าใช้จ่ายเหล่านี้ให้อยู่ในระดับที่หยาบขึ้น ตัวอย่างเช่นแทนที่จะจ่ายค่าใช้จ่ายนามธรรมเชิงนามธรรมสำหรับอนุภาคเดี่ยวเราอาจผลักดันต้นทุนนั้นไปที่ระดับของระบบอนุภาค / ตัวส่งซึ่งทำให้อนุภาคมีประสิทธิภาพในรายละเอียดการนำไปปฏิบัติและ / หรือข้อมูลดิบของการรวบรวมอนุภาคนี้อย่างมีประสิทธิภาพ
ดังนั้นการออกแบบเชิงวัตถุจึงไม่จำเป็นต้องขัดกับการออกแบบเพื่อประสิทธิภาพ (ไม่ว่าจะเป็นความหน่วงหรือปริมาณงาน) แต่อาจมีการล่อลวงในภาษาที่มุ่งเน้นไปที่การสร้างแบบจำลองวัตถุเม็ดเล็ก ๆ มากขึ้นและไม่มีเครื่องมือเพิ่มประสิทธิภาพล่าสุด ช่วยด้วย. มันไม่สามารถทำสิ่งต่าง ๆ เช่นเชื่อมโยงคลาสที่เป็นตัวแทนของจุดเดียวในแบบที่ให้ผลการแทน SOA ที่มีประสิทธิภาพสำหรับรูปแบบการเข้าถึงหน่วยความจำของซอฟต์แวร์ คอลเลกชันของจุดที่มีการออกแบบส่วนต่อประสานที่จำลองในระดับของความหยาบเสนอโอกาสนั้นและอนุญาตให้ทำซ้ำไปยังโซลูชันที่เหมาะสมที่สุดและมากขึ้นตามความจำเป็น การออกแบบดังกล่าวได้รับการออกแบบสำหรับหน่วยความจำขนาดใหญ่ *
* สังเกตการโฟกัสที่หน่วยความจำที่นี่ไม่ใช่ข้อมูลเนื่องจากการทำงานในพื้นที่ที่มีความสำคัญต่อประสิทธิภาพเป็นเวลานานมักจะเปลี่ยนมุมมองของชนิดข้อมูลและโครงสร้างข้อมูลและดูว่าพวกเขาเชื่อมต่อกับหน่วยความจำอย่างไร แผนผังการค้นหาแบบไบนารี่ไม่ได้กลายเป็นเพียงความซับซ้อนของลอการิทึมเท่านั้นในกรณีเช่นนี้อาจเป็นหน่วยความจำที่แตกต่างกันและแคชที่ไม่เป็นมิตรสำหรับโหนดต้นไม้ยกเว้นว่าได้รับความช่วยเหลือจากตัวจัดสรรแบบคงที่ มุมมองไม่ได้ยกเลิกความซับซ้อนของอัลกอริทึม แต่จะเห็นว่ามันไม่ได้เป็นอิสระจากโครงร่างหน่วยความจำอีกต่อไป นอกจากนี้ยังเริ่มเห็นการทำงานซ้ำ ๆ เกี่ยวกับการทำซ้ำการเข้าถึงหน่วยความจำ *
การออกแบบที่มีประสิทธิภาพที่สำคัญจำนวนมากนั้นสามารถเข้ากันได้กับแนวคิดการออกแบบอินเตอร์เฟสระดับสูงที่มนุษย์เข้าใจและใช้งานได้ง่าย ความแตกต่างคือ"ระดับสูง"ในบริบทนี้จะเกี่ยวกับการรวมหน่วยความจำจำนวนมากส่วนต่อประสานที่จำลองแบบสำหรับการรวบรวมข้อมูลขนาดใหญ่ที่อาจเกิดขึ้นและการใช้งานภายใต้ประทุนที่อาจอยู่ในระดับต่ำ การเปรียบเทียบด้วยภาพอาจเป็นรถที่สบายและขับและจัดการได้ง่ายและปลอดภัยมากในขณะที่อยู่ในระดับความเร็วของเสียง แต่ถ้าคุณเปิดฝากระโปรงก็จะมีปีศาจหายใจไฟอยู่ข้างใน
ด้วยการออกแบบที่หยาบก็มีแนวโน้มที่จะเป็นวิธีที่ง่ายขึ้นที่จะให้รูปแบบการล็อคที่มีประสิทธิภาพมากขึ้นและใช้ประโยชน์จากความขนานในโค้ด (มัลติเธรดเป็นหัวข้อที่ละเอียดถี่ถ้วนที่ฉันจะข้ามที่นี่)
พูลหน่วยความจำ
ลักษณะสำคัญของการเขียนโปรแกรมแบบความหน่วงต่ำอาจเป็นการควบคุมหน่วยความจำอย่างชัดเจนเพื่อปรับปรุงท้องถิ่นของการอ้างอิงรวมถึงความเร็วทั่วไปของการจัดสรรและการจัดสรรหน่วยความจำ หน่วยความจำการจัดสรรแบบกำหนดเองรวมหน่วยความจำแบบสะท้อนความคิดการออกแบบชนิดเดียวกันกับที่เราอธิบายไว้ มันถูกออกแบบมาสำหรับกลุ่ม ; มันออกแบบในระดับหยาบ มันจัดสรรหน่วยความจำในบล็อกขนาดใหญ่และพูลหน่วยความจำที่จัดสรรไว้แล้วในกลุ่มเล็ก ๆ
แนวคิดนี้เหมือนกันกับการผลักสิ่งที่มีราคาแพง (การจัดสรรก้อนหน่วยความจำกับตัวจัดสรรวัตถุประสงค์ทั่วไปเช่น) ไปที่ระดับ coarser และ coarser สระว่ายน้ำหน่วยความจำที่ถูกออกแบบมาสำหรับการจัดการกับหน่วยความจำในกลุ่ม
ประเภทระบบแยกหน่วยความจำ
ปัญหาอย่างหนึ่งของการออกแบบเชิงวัตถุในภาษาใด ๆ ก็คือมันมักจะต้องการแนะนำโครงสร้างข้อมูลและโครงสร้างข้อมูลที่ผู้ใช้กำหนดจำนวนมาก ประเภทเหล่านั้นสามารถต้องการได้รับการจัดสรรเป็นชิ้นเล็ก ๆ หากมีการจัดสรรแบบไดนามิก
ตัวอย่างทั่วไปใน C ++ สำหรับกรณีที่ต้องการ polymorphism ซึ่งการทดลองตามธรรมชาติคือการจัดสรรแต่ละคลาสย่อยของคลาสย่อยกับตัวจัดสรรหน่วยความจำทั่วไป
สิ่งนี้จบลงด้วยการแบ่งเลย์เอาต์ของหน่วยความจำที่ต่อเนื่องกันออกเป็นบิตบิตและชิ้นส่วนที่กระจัดกระจายไปตามช่วงที่อยู่
เขตข้อมูลที่มีความต้องการต่ำสุดแฝงพูดติดอ่างฟรีการตอบสนองที่กำหนดอาจจะเป็นสถานที่หนึ่งที่ฮอตสปอตไม่เคยต้มลงไปเป็นคอขวดเดียวที่ไร้ประสิทธิภาพเล็กสามารถจริงอย่างแท้จริงชนิดของการ"สะสม" (สิ่งที่ผู้คนจำนวนมากจินตนาการ เกิดขึ้นอย่างไม่ถูกต้องกับผู้สร้างโปรไฟล์เพื่อให้พวกเขาอยู่ในการตรวจสอบ แต่ในเขตข้อมูลที่ขับเคลื่อนด้วยความล่าช้าอาจมีบางกรณีที่หายากที่ความไร้ประสิทธิภาพเล็ก ๆ น้อย ๆ สะสม) และสาเหตุที่พบบ่อยที่สุดสำหรับการสะสมเช่นนี้ก็คือ: การจัดสรรหน่วยความจำที่เล็กมากเกินไปทั่วทุกแห่ง
ในภาษาเช่น Java มันจะมีประโยชน์ในการใช้อาร์เรย์ของชนิดข้อมูลเก่าแบบเก่า ๆ ได้มากขึ้นเมื่อเป็นไปได้สำหรับพื้นที่คอขวด (พื้นที่ที่ประมวลผลในลูปคับ) เช่นอาร์เรย์ของint
(แต่ยังคงอยู่ด้านหลังอินเตอร์เฟสระดับสูงขนาดใหญ่) แทน เป็นArrayList
ของที่ผู้ใช้กำหนดInteger
วัตถุ วิธีนี้จะหลีกเลี่ยงการแยกหน่วยความจำที่โดยทั่วไปแล้วจะมาพร้อมกับส่วนหลัง ใน C ++ เราไม่จำเป็นต้องลดโครงสร้างลงมากนักหากรูปแบบการจัดสรรหน่วยความจำของเรามีประสิทธิภาพเนื่องจากประเภทที่ผู้ใช้กำหนดสามารถจัดสรรได้อย่างต่อเนื่องและแม้ในบริบทของคอนเทนเนอร์ทั่วไป
การรวมหน่วยความจำกลับมารวมกัน
วิธีแก้ไขที่นี่คือการเข้าถึงสำหรับตัวจัดสรรแบบกำหนดเองสำหรับชนิดข้อมูลที่เป็นเนื้อเดียวกันและอาจเป็นไปได้สำหรับชนิดข้อมูลที่เป็นเนื้อเดียวกัน เมื่อชนิดข้อมูลขนาดเล็กและโครงสร้างข้อมูลถูกทำให้แบนเป็นบิตและไบต์ในหน่วยความจำพวกมันจะมีลักษณะที่เป็นเนื้อเดียวกัน เมื่อเราไม่ได้ดูจากความคิดที่เป็นศูนย์กลางของหน่วยความจำระบบประเภทของภาษาการเขียนโปรแกรม "ต้องการ" เพื่อแยก / แยกส่วนของหน่วยความจำที่ต่อเนื่องกันซึ่งอาจแยกออกเป็นชิ้นเล็ก ๆ กระจัดกระจาย
สแต็กใช้การมุ่งเน้นที่หน่วยความจำเป็นศูนย์กลางเพื่อหลีกเลี่ยงปัญหานี้และอาจจัดเก็บชุดค่าผสมที่เป็นไปได้ของอินสแตนซ์ชนิดที่ผู้ใช้กำหนดเองที่เป็นไปได้ การใช้กองซ้อนให้มากขึ้นเป็นความคิดที่ดีเมื่อเป็นไปได้เพราะส่วนบนสุดของมันมักจะนั่งอยู่ในสายแคช แต่เรายังสามารถออกแบบตัวจัดสรรหน่วยความจำที่เลียนแบบลักษณะเหล่านี้บางอย่างโดยไม่มีรูปแบบ LIFO chunks แม้สำหรับการจัดสรรหน่วยความจำที่ซับซ้อนมากขึ้นและรูปแบบการจัดสรรคืน
ฮาร์ดแวร์ที่ทันสมัยได้รับการออกแบบให้อยู่ในระดับสูงสุดเมื่อทำการประมวลผลบล็อกหน่วยความจำที่ต่อเนื่องกัน (การเข้าถึงสายแคชเดียวกันหน้าเดียวกันเช่นซ้ำ ๆ ) คำหลักนั้นมีความเกี่ยวข้องเนื่องจากจะเป็นประโยชน์เฉพาะในกรณีที่มีข้อมูลที่น่าสนใจโดยรอบ ดังนั้นกุญแจจำนวนมาก (แต่ก็มีความยากลำบาก) ในการปฏิบัติงานคือการรวมกลุ่มของหน่วยความจำที่แยกกลับมารวมกันอีกครั้งในบล็อกที่ต่อเนื่องกันซึ่งเข้าถึงได้อย่างครบถ้วน ระบบประเภทรวยโดยเฉพาะอย่างยิ่งประเภทที่ผู้ใช้กำหนดในภาษาการเขียนโปรแกรมอาจเป็นอุปสรรคที่ใหญ่ที่สุดที่นี่ แต่เราสามารถเข้าถึงและแก้ไขปัญหาได้ตลอดเวลาผ่านตัวปันส่วนที่กำหนดเองและ / หรือการออกแบบเป็นกลุ่มตามความเหมาะสม
น่าเกลียด
"Ugly" ยากที่จะพูด มันเป็นตัวชี้วัดแบบอัตนัยและคนที่ทำงานในสาขาที่มีประสิทธิภาพสูงจะเริ่มเปลี่ยนความคิดของพวกเขาในเรื่อง "ความงาม" ไปสู่สิ่งที่มุ่งเน้นข้อมูลมากขึ้นและมุ่งเน้นไปที่อินเตอร์เฟสที่ประมวลผลเป็นกลุ่ม
เป็นอันตราย
"อันตราย" อาจจะง่ายกว่า โดยทั่วไปประสิทธิภาพมีแนวโน้มที่จะต้องการเข้าถึงโค้ดระดับล่าง ยกตัวอย่างเช่นการนำตัวจัดสรรหน่วยความจำไปใช้นั้นเป็นไปไม่ได้หากไม่มีการเข้าถึงข้อมูลและทำงานในระดับบิตและไบต์ที่เป็นอันตราย เป็นผลให้สามารถช่วยเพิ่มความสำคัญในขั้นตอนการทดสอบอย่างระมัดระวังในระบบย่อยที่มีความสำคัญต่อประสิทธิภาพเหล่านี้โดยปรับขนาดความละเอียดของการทดสอบโดยใช้ระดับการปรับให้เหมาะสมที่สุด
ความงาม
แต่ทั้งหมดนี้จะอยู่ในระดับรายละเอียดการใช้งาน ในทั้งความคิดที่มีขนาดใหญ่และมีความสำคัญต่อประสิทธิภาพ "ความงาม" มีแนวโน้มที่จะเปลี่ยนไปสู่การออกแบบอินเตอร์เฟสมากกว่ารายละเอียดการใช้งาน มันจะกลายเป็นลำดับความสำคัญที่สูงขึ้นอย่างทวีคูณในการค้นหาอินเทอร์เฟซ "สวยงาม" ใช้งานได้ปลอดภัยและมีประสิทธิภาพมากกว่าการใช้งานเนื่องจากการมีเพศสัมพันธ์และการแตกซ้อนที่สามารถเกิดขึ้นได้เมื่อเผชิญหน้ากับการเปลี่ยนแปลงการออกแบบอินเตอร์เฟส การใช้งานสามารถสลับออกได้ตลอดเวลา โดยทั่วไปเราจะเน้นไปที่ประสิทธิภาพตามที่ต้องการและชี้ให้เห็นจากการวัด กุญแจที่มีการออกแบบส่วนต่อประสานคือการสร้างโมเดลในระดับที่หยาบพอที่จะออกจากห้องสำหรับการทำซ้ำดังกล่าวโดยไม่ทำให้ทั้งระบบพัง
ในความเป็นจริงฉันขอแนะนำว่าการให้ความสำคัญกับการพัฒนาที่มีประสิทธิภาพนั้นมักจะให้ความสำคัญกับความปลอดภัยการทดสอบการบำรุงรักษาเป็นเพียงสาวกของ SE โดยทั่วไปเนื่องจาก codebase ขนาดใหญ่ซึ่งมีประสิทธิภาพจำนวนมาก - ระบบย่อยที่สำคัญ (ระบบอนุภาค, อัลกอริทึมการประมวลผลภาพ, การประมวลผลวิดีโอ, เสียงตอบรับ, raytracers, เครื่องมือตาข่าย, ฯลฯ ) จะต้องให้ความสนใจอย่างใกล้ชิดกับวิศวกรรมซอฟต์แวร์เพื่อหลีกเลี่ยงการจมน้ำในฝันร้ายการบำรุงรักษา ไม่ใช่เรื่องบังเอิญที่บ่อยครั้งที่ผลิตภัณฑ์ที่มีประสิทธิภาพสูงสุดอย่างน่าอัศจรรย์นั้นยังมีข้อผิดพลาดน้อยที่สุด
TL; DR
อย่างไรก็ตามนี่คือสิ่งที่ฉันใช้ในเรื่องตั้งแต่ลำดับความสำคัญในด้านประสิทธิภาพการทำงานที่สำคัญอย่างแท้จริงสิ่งที่สามารถลดความล่าช้าและทำให้ความไร้ประสิทธิภาพเล็ก ๆ น้อย ๆ ที่จะสะสมและสิ่งที่ถือเป็น "ความงาม" จริง ๆ