ทำให้ฉันสงสัยว่า Multithreading มีความสำคัญอย่างไรในสถานการณ์ปัจจุบันของอุตสาหกรรม
ในด้านประสิทธิภาพที่สำคัญซึ่งประสิทธิภาพไม่ได้มาจากรหัสของบุคคลที่สามที่กำลังยกระดับสูง แต่เป็นของเราเองฉันมักจะพิจารณาสิ่งต่าง ๆ ตามลำดับความสำคัญนี้จากมุมมองของ CPU (GPU เป็นสัญลักษณ์แทนฉันชนะ เข้าไป):
- ประสิทธิภาพหน่วยความจำ (เช่นตำแหน่งของการอ้างอิง)
- อัลกอริทึม
- multithreading
- SIMD
- การเพิ่มประสิทธิภาพอื่น ๆ (คำแนะนำการคาดคะเนสาขาคงที่เช่น)
โปรดทราบว่านี่คือรายการที่ไม่ได้ขึ้นอยู่กับความสำคัญเพียงอย่างเดียว แต่การเปลี่ยนแปลงอื่น ๆ เช่นผลกระทบที่พวกเขามีต่อการบำรุงรักษาวิธีที่ตรงไปตรงมาพวกเขา (ถ้าไม่คุ้มค่าพิจารณาเพิ่มเติมล่วงหน้า) การโต้ตอบกับผู้อื่นในรายการเป็นต้น
ประสิทธิภาพของหน่วยความจำ
ส่วนใหญ่อาจจะแปลกใจที่ฉันเลือกประสิทธิภาพหน่วยความจำมากกว่าอัลกอริทึม เป็นเพราะประสิทธิภาพหน่วยความจำโต้ตอบกับ 4 รายการอื่น ๆ ในรายการนี้และเป็นเพราะการพิจารณาของมันมักจะมากในหมวดหมู่ "การออกแบบ" มากกว่า "การนำไปใช้" หมวดหมู่ มีปัญหากับไก่หรือไข่เล็กน้อยเนื่องจากความเข้าใจประสิทธิภาพของหน่วยความจำมักต้องพิจารณาทั้ง 4 รายการในรายการขณะที่อีก 4 รายการต้องการการพิจารณาประสิทธิภาพของหน่วยความจำด้วย แต่มันเป็นหัวใจของทุกสิ่ง
ตัวอย่างเช่นถ้าเรามีความต้องการโครงสร้างข้อมูลที่ให้การเข้าถึงลำดับเชิงเส้นเวลาและการแทรกเวลาคงที่ไปด้านหลังและไม่มีสิ่งอื่นใดสำหรับองค์ประกอบขนาดเล็กตัวเลือกที่ไร้เดียงสาที่นี่เพื่อเข้าถึงนั้นจะเป็นรายการที่เชื่อมโยงกัน ที่ไม่คำนึงถึงประสิทธิภาพของหน่วยความจำ เมื่อเราพิจารณาประสิทธิภาพของหน่วยความจำในการผสมผสานเราจะเลือกโครงสร้างที่ต่อเนื่องกันมากขึ้นในสถานการณ์นี้เช่นโครงสร้างที่อิงอาร์เรย์ที่เติบโตได้หรือโหนดที่ต่อเนื่องได้มากกว่า (เช่น: หนึ่งที่เก็บองค์ประกอบ 128 องค์ประกอบในโหนด) ที่เชื่อมโยงกันหรืออย่างน้อยที่สุด รายการที่เชื่อมโยงซึ่งสำรองโดยตัวจัดสรรพูล สิ่งเหล่านี้มีความได้เปรียบอย่างมากทั้งๆที่มีความซับซ้อนของอัลกอริทึมเดียวกัน ในทำนองเดียวกันเรามักเลือกอาร์เรย์ที่รวดเร็วกว่าการเรียงแบบผสานแม้ว่าความซับซ้อนของอัลกอริทึมที่ต่ำกว่านั้นก็เนื่องมาจากประสิทธิภาพของหน่วยความจำ
ในทำนองเดียวกันเราไม่สามารถทำการมัลติเธรดที่มีประสิทธิภาพได้หากรูปแบบการเข้าถึงหน่วยความจำของเรานั้นละเอียดและกระจัดกระจายในลักษณะที่เราสิ้นสุดการเพิ่มจำนวนการแบ่งปันที่ผิดพลาดสูงสุดในขณะที่ล็อคในระดับที่ละเอียดที่สุดในรหัส ดังนั้นประสิทธิภาพหน่วยความจำจึงเพิ่มประสิทธิภาพมัลติเธรดให้มากขึ้น เป็นข้อกำหนดเบื้องต้นในการรับประโยชน์สูงสุดจากเธรด
ทุกรายการด้านบนในรายการมีการโต้ตอบที่ซับซ้อนกับข้อมูลและมุ่งเน้นไปที่วิธีการแสดงข้อมูลในท้ายที่สุดในหลอดเลือดดำของประสิทธิภาพของหน่วยความจำ ทุก ๆ สิ่งเหล่านี้ด้านบนสามารถถูกคอขวดด้วยวิธีที่ไม่เหมาะสมในการแสดงหรือเข้าถึงข้อมูล
อีกเหตุผลหนึ่งที่ทำให้ประสิทธิภาพของหน่วยความจำมีความสำคัญมากคือมันสามารถใช้งานได้ตลอดทั้ง codebase ทั้งหมด โดยทั่วไปเมื่อผู้คนจินตนาการว่าความไร้ประสิทธิภาพสะสมจากงานเล็ก ๆ น้อย ๆ ที่นี่และที่นั่นมันเป็นสัญญาณว่าพวกเขาต้องคว้า profiler แต่ฟิลด์ที่มีความหน่วงต่ำหรือที่เกี่ยวข้องกับฮาร์ดแวร์ที่มี จำกัด จะพบจริงแม้หลังจากการทำโปรไฟล์เซสชันที่ระบุว่าไม่มีฮอตสปอตที่ชัดเจน (แค่กระจายไปทั่วสถานที่) ในโค้ดเบสที่ไม่มีประสิทธิภาพอย่างโจ่งแจ้งกับวิธีการจัดสรรคัดลอกและ การเข้าถึงหน่วยความจำ โดยทั่วไปแล้วนี่เป็นเพียงครั้งเดียวที่ codebase ทั้งหมดสามารถไวต่อความกังวลด้านประสิทธิภาพที่อาจนำไปสู่มาตรฐานชุดใหม่ที่นำไปใช้ตลอดทั้ง codebase และประสิทธิภาพของหน่วยความจำมักเป็นหัวใจของมัน
อัลกอริทึม
ตัวเลือกนี้ค่อนข้างได้รับเนื่องจากตัวเลือกในอัลกอริทึมการเรียงลำดับสามารถสร้างความแตกต่างระหว่างอินพุทขนาดใหญ่ที่ใช้เวลาเป็นเดือนในการจัดเรียงกับวินาทีในการจัดเรียง มันทำให้เกิดผลกระทบที่ยิ่งใหญ่ที่สุดของทั้งหมดถ้าตัวเลือกอยู่ระหว่าง, พูด, อัลกอริธึม sub-par หรือลูกบาศก์ลูกบาศก์ย่อยจริง ๆ และ linearith หนึ่งหรือระหว่างเชิงเส้นและลอการิทึมหรือค่าคงที่อย่างน้อยก็จนกว่าเราจะมี 1,000,000 เครื่องหลัก ประสิทธิภาพจะยิ่งมีความสำคัญมากยิ่งขึ้น)
มันไม่ได้อยู่ในรายชื่อส่วนบุคคลของฉัน แต่เนื่องจากใครก็ตามที่มีความสามารถในสาขาของพวกเขาจะรู้ว่าใช้โครงสร้างการเร่งความเร็วสำหรับการเลือกเฟินดัมเช่นเรากำลังอิ่มตัวด้วยความรู้อัลกอริทึมและรู้สิ่งต่าง ๆ เช่นการใช้ตัวแปร ต้นไม้ radix สำหรับการค้นหาคำนำหน้าเป็นสิ่งที่ทารก การขาดความรู้พื้นฐานประเภทนี้ในสาขาที่เรากำลังดำเนินการอยู่นั้นประสิทธิภาพของอัลกอริทึมจะสูงขึ้นอย่างแน่นอน แต่บ่อยครั้งที่ประสิทธิภาพของอัลกอริทึมนั้นเล็กน้อย
การประดิษฐ์อัลกอริธึมใหม่อาจเป็นสิ่งจำเป็นในบางสาขา (เช่น: ในการประมวลผลแบบตาข่ายฉันต้องประดิษฐ์หลายร้อยเนื่องจากไม่เคยมีมาก่อนหรือการใช้งานคุณสมบัติที่คล้ายกันในผลิตภัณฑ์อื่นเป็นความลับกรรมสิทธิ์ไม่เผยแพร่ในกระดาษ ) อย่างไรก็ตามเมื่อเราผ่านส่วนการแก้ไขปัญหาและค้นหาวิธีที่จะได้รับผลลัพธ์ที่ถูกต้องและเมื่อประสิทธิภาพกลายเป็นเป้าหมายวิธีเดียวที่จะได้รับจริงๆคือการพิจารณาว่าเราโต้ตอบกับข้อมูล (หน่วยความจำ) อย่างไร หากไม่เข้าใจประสิทธิภาพของหน่วยความจำอัลกอริธึมใหม่อาจซับซ้อนโดยไม่ต้องใช้ความพยายามอย่างไร้ประโยชน์เพื่อให้เร็วขึ้นเมื่อสิ่งเดียวที่จำเป็นคือการพิจารณาประสิทธิภาพของหน่วยความจำให้มากขึ้นเพื่อให้ได้อัลกอริธึมที่ง่ายกว่า
สุดท้ายอัลกอริทึมมักจะอยู่ในหมวดหมู่ "การใช้งาน" มากกว่าประสิทธิภาพของหน่วยความจำ พวกเขามักจะง่ายขึ้นในการปรับปรุงในปัญหาหลังถึงแม้จะมีอัลกอริทึมย่อยที่ดีที่สุดที่ใช้ในตอนแรก ตัวอย่างเช่นอัลกอริธึมการประมวลผลภาพที่ด้อยคุณภาพมักจะถูกนำไปใช้ในที่เดียวในฐานโค้ด มันสามารถสลับกับดีกว่าในภายหลัง อย่างไรก็ตามหากอัลกอริธึมการประมวลผลภาพทั้งหมดถูกเชื่อมโยงกับPixel
อินเทอร์เฟซที่มีการแสดงหน่วยความจำย่อยที่เหมาะสมที่สุด แต่วิธีเดียวที่จะแก้ไขได้คือการเปลี่ยนวิธีแสดงพิกเซลหลายพิกเซล (ไม่ใช่หนึ่งเดียว) เรามักจะ SOL และจะต้องเขียน codebase ให้สมบูรณ์เพื่อImage
อินเตอร์เฟซ. สิ่งเดียวกันสำหรับการแทนที่อัลกอริธึมการเรียงลำดับ - โดยปกติแล้วจะเป็นรายละเอียดการใช้งานในขณะที่การเปลี่ยนแปลงที่สมบูรณ์เพื่อแสดงข้อมูลที่ถูกจัดเรียงหรือวิธีการส่งผ่านข้อความอาจต้องมีการออกแบบอินเตอร์เฟสใหม่
multithreading
มัลติเธรดเป็นสิ่งที่ยากในบริบทของประสิทธิภาพเนื่องจากเป็นการเพิ่มประสิทธิภาพระดับไมโครที่เล่นกับลักษณะของฮาร์ดแวร์ แต่ฮาร์ดแวร์ของเรากำลังขยายไปในทิศทางนั้น ฉันมีเพื่อนที่มี 32 คอร์ (ฉันมีเพียง 4)
แต่การใช้ mulithreading เป็นหนึ่งในการเพิ่มประสิทธิภาพไมโครที่อันตรายที่สุดที่ผู้เชี่ยวชาญอาจทราบหากใช้เพื่อเพิ่มความเร็วของซอฟต์แวร์ สภาพการแข่งขันนั้นค่อนข้างเป็นข้อผิดพลาดที่ร้ายแรงที่สุดเท่าที่จะเป็นไปได้เนื่องจากมันไม่สามารถกำหนดได้ในธรรมชาติ (อาจปรากฏขึ้นทุก ๆ สองสามเดือนในเครื่องของนักพัฒนาในเวลาที่ไม่สะดวกที่สุดนอกบริบทการดีบักหากทั้งหมด) ดังนั้นจึงมีความเป็นไปได้ที่การย่อยสลายเชิงลบมากที่สุดเกี่ยวกับความสามารถในการบำรุงรักษาและความถูกต้องที่อาจเกิดขึ้นของรหัสทั้งหมดโดยเฉพาะอย่างยิ่งเนื่องจากข้อบกพร่องที่เกี่ยวข้องกับมัลติเธรดสามารถบินได้อย่างง่ายดายภายใต้เรดาร์
อย่างไรก็ตามมันมีความสำคัญมาก แม้ว่าบางครั้งมันอาจยังไม่ดีกว่าอย่างเช่นประสิทธิภาพของหน่วยความจำ (ซึ่งบางครั้งอาจทำให้เร็วขึ้นเป็นร้อยเท่า) จากจำนวนคอร์ที่เรามีอยู่ตอนนี้ แต่เราก็เห็นคอร์มากขึ้นเรื่อย ๆ แน่นอนว่าแม้จะมีเครื่อง 100 คอร์ฉันยังคงใส่ประสิทธิภาพหน่วยความจำไว้ด้านบนของรายการเนื่องจากประสิทธิภาพของเธรดนั้นเป็นไปไม่ได้หากไม่มีมัน โปรแกรมสามารถใช้ร้อยเธรดในเครื่องดังกล่าวและยังคงช้าในการขาดการนำเสนอหน่วยความจำที่มีประสิทธิภาพและรูปแบบการเข้าถึง (ซึ่งจะผูกกับรูปแบบการล็อค)
SIMD
SIMD นั้นค่อนข้างแปลกใจเนื่องจากการลงทะเบียนนั้นกว้างขึ้นจริง ๆ ด้วยแผนการที่จะขยายให้กว้างขึ้น เดิมเราเห็นการลงทะเบียน MMX 64- บิตตามด้วยการลงทะเบียน XMM 128- บิตที่มีความสามารถในการดำเนินการ SPFP 4 แบบขนาน ตอนนี้เราเห็นการลงทะเบียน YMM 256 บิตที่มีความสามารถ 8 แบบขนาน และมีแผนที่วางไว้สำหรับการลงทะเบียน 512 บิตซึ่งจะอนุญาตให้ 16 แบบขนาน
สิ่งเหล่านี้จะโต้ตอบและทวีคูณกับประสิทธิภาพของการทำมัลติเธรด แต่ SIMD สามารถลดความสามารถในการบำรุงรักษาได้เช่นเดียวกับมัลติเธรด แม้ว่าข้อผิดพลาดที่เกี่ยวข้องกับพวกเขาไม่จำเป็นต้องยากที่จะทำซ้ำและแก้ไขตามสภาพการหยุดชะงักหรือการแข่งขัน แต่ความสะดวกในการพกพานั้นไม่สะดวกและทำให้มั่นใจได้ว่ารหัสสามารถทำงานบนเครื่องของทุกคน (และใช้คำแนะนำที่เหมาะสม อึดอัด
อีกสิ่งหนึ่งคือในขณะที่คอมไพเลอร์ในปัจจุบันมักจะไม่เอาชนะรหัส SIMD ที่เขียนโดยผู้เชี่ยวชาญ แต่พวกเขาก็เอาชนะความพยายามที่ไร้เดียงสาได้อย่างง่ายดาย พวกเขาอาจปรับปรุงไปจนถึงจุดที่เราไม่ต้องทำด้วยตนเองอีกต่อไปหรืออย่างน้อยก็ไม่ต้องทำคู่มือเพื่อเขียนรหัสที่แท้จริงหรือชุดประกอบแบบตรง (อาจเป็นเพียงแนวทางของมนุษย์)
อีกครั้งแม้ว่าไม่มีเลย์เอาต์หน่วยความจำที่มีประสิทธิภาพสำหรับการประมวลผลแบบเวกเตอร์ SIMD ไม่มีประโยชน์ เราจะลงเอยเพียงแค่โหลดหนึ่งสเกลาร์ฟิลด์ในการลงทะเบียนแบบกว้างเท่านั้นเพื่อดำเนินการหนึ่งอย่างในนั้น หัวใจของรายการเหล่านี้คือการพึ่งพาโครงร่างหน่วยความจำที่มีประสิทธิภาพอย่างแท้จริง
การเพิ่มประสิทธิภาพอื่น ๆ
สิ่งเหล่านี้มักจะเป็นสิ่งที่ฉันอยากจะแนะนำให้เราเริ่มเรียกว่า "ไมโคร" ทุกวันนี้หากคำแนะนำไม่เพียง แต่จะให้ความสำคัญกับอัลกอริธึม แต่ไปสู่การเปลี่ยนแปลงที่ส่งผลกระทบต่อประสิทธิภาพการทำงาน
บ่อยครั้งที่การพยายามปรับให้เหมาะสมที่สุดสำหรับการทำนายสาขาจำเป็นต้องเปลี่ยนอัลกอริธึมหรือประสิทธิภาพของหน่วยความจำเช่นหากพยายามผ่านคำแนะนำและการจัดเรียงรหัสใหม่สำหรับการคาดการณ์แบบคงที่ซึ่งมีแนวโน้มที่จะปรับปรุงการดำเนินการครั้งแรก ไม่บ่อยมากเล็กน้อย
กลับไปที่มัลติเธรดเพื่อประสิทธิภาพ
อย่างไรก็ตามการมัลติเธรดสำคัญกับบริบทประสิทธิภาพเป็นอย่างไร บนเครื่อง 4 แกนของฉันมันสามารถสร้างสิ่งต่าง ๆ ได้เร็วขึ้นประมาณ 5 เท่า (สิ่งที่ฉันสามารถทำได้ด้วยการทำไฮเปอร์เธรด) มันจะสำคัญกว่าสำหรับเพื่อนร่วมงานของฉันที่มี 32 คอร์ และจะมีความสำคัญเพิ่มมากขึ้นในอนาคต
มันสำคัญมาก แต่ก็ไม่มีประโยชน์ที่จะโยนเธรดที่เป็นปัญหาหากประสิทธิภาพของหน่วยความจำไม่อยู่ที่นั่นเพื่ออนุญาตให้ใช้การล็อกอย่าง จำกัด เพื่อลดการแบ่งปันที่ผิดพลาดเป็นต้น
มัลติเธรดนอกประสิทธิภาพ
การมัลติเธรดไม่ได้เกี่ยวกับประสิทธิภาพที่แท้จริงในแง่ของปริมาณงานที่ตรงไปตรงมา บางครั้งก็ใช้เพื่อถ่วงโหลดแม้ในปริมาณที่เป็นไปได้ในการรับส่งข้อมูลเพื่อปรับปรุงการตอบสนองต่อผู้ใช้หรือเพื่อให้ผู้ใช้สามารถทำงานหลายอย่างได้มากขึ้นโดยไม่ต้องรอให้สิ่งต่าง ๆ เสร็จสิ้น
ในกรณีเหล่านั้นฉันขอแนะนำว่ามัลติเธรดเพิ่มสูงขึ้นไปด้านบน (อาจสูงกว่าประสิทธิภาพของหน่วยความจำ) เนื่องจากมันเกี่ยวกับการออกแบบของผู้ใช้มากกว่าที่จะใช้ประโยชน์จากฮาร์ดแวร์ให้ได้มากที่สุด มันมักจะมีอิทธิพลต่อการออกแบบส่วนต่อประสานและวิธีที่เราจัดโครงสร้างรหัสฐานทั้งหมดของเราในสถานการณ์ดังกล่าว
เมื่อเราไม่เพียงแค่ขนานกับวงวนที่แน่นหนาในการเข้าถึงโครงสร้างข้อมูลขนาดใหญ่มัลติเธรดก็จะอยู่ในหมวดหมู่ "การออกแบบ" ที่ไม่ยอมใครง่ายๆจริงๆ
ดังนั้นในกรณีเหล่านั้นฉันจะบอกว่าการพิจารณามัลติเธรดอย่างตรงไปตรงมานั้นสำคัญยิ่งกว่าการเป็นตัวแทนและการเข้าถึงหน่วยความจำ