นักพัฒนา V8 ที่นี่ ด้วยจำนวนความสนใจในคำถามนี้และการขาดคำตอบอื่น ๆ ฉันสามารถให้ภาพนี้ได้ ฉันกลัวว่ามันจะไม่ใช่คำตอบที่คุณหวังไว้
มีชุดแนวทางในการเขียนโปรแกรมในขณะที่อยู่ในโลกของอาร์เรย์ SMI ที่บรรจุ (ตัวอย่าง) หรือไม่?
คำตอบสั้น ๆ : มันอยู่ที่นี่: const guidelines = ["keep your integers small enough"]
.
คำตอบอีกต่อไป: การให้แนวทางที่ครอบคลุมนั้นเป็นเรื่องยากด้วยเหตุผลหลายประการ โดยทั่วไปแล้วความคิดเห็นของเราคือผู้พัฒนา JavaScript ควรเขียนโค้ดที่เหมาะสมกับพวกเขาและกรณีการใช้งานและนักพัฒนาเครื่องมือ JavaScript ควรรู้วิธีเรียกใช้โค้ดนั้นอย่างรวดเร็วในเอ็นจิ้นของพวกเขา ในทางกลับกันมีข้อ จำกัด บางประการสำหรับอุดมคตินั้นในแง่ที่ว่ารูปแบบการเข้ารหัสบางอย่างจะมีค่าใช้จ่ายประสิทธิภาพสูงกว่าคนอื่นเสมอโดยไม่คำนึงถึงตัวเลือกการใช้งานเครื่องยนต์และความพยายามเพิ่มประสิทธิภาพ
เมื่อเราพูดถึงคำแนะนำเกี่ยวกับประสิทธิภาพเราพยายามระลึกไว้เสมอและประเมินอย่างรอบคอบว่าคำแนะนำใดมีโอกาสสูงที่จะใช้งานได้กับเครื่องยนต์จำนวนมากและเป็นเวลาหลายปีและยังมีนิสัยสำนึกผิด / ไม่ล่วงล้ำ
กลับไปที่ตัวอย่างในมือ: การใช้ Smis ภายในควรจะเป็นรายละเอียดการใช้งานที่รหัสผู้ใช้ไม่จำเป็นต้องรู้ มันจะทำให้บางกรณีมีประสิทธิภาพมากขึ้นและไม่ควรเจ็บในกรณีอื่น มีบางเครื่องมือที่ใช้ Smis (ตัวอย่างเช่น AFAIK Firefox / Spidermonkey ที่ผ่านมาไม่ได้; ฉันได้ยินมาว่าในบางกรณีพวกเขาใช้ Smis ในทุกวันนี้ แต่ฉันไม่ทราบรายละเอียดใด ๆ เรื่อง) ใน V8 ขนาดของ Smis เป็นรายละเอียดภายในและมีการเปลี่ยนแปลงตามเวลาและรุ่นจริง ๆ บนแพลตฟอร์ม 32 บิตซึ่งเคยเป็นกรณีใช้งานส่วนใหญ่ Smis เป็นจำนวนเต็ม 31 บิตที่ลงนามแล้วเสมอ บนแพลตฟอร์ม 64 บิตที่พวกเขาเคยเป็นจำนวนเต็ม 32 บิตซึ่งดูเหมือนว่าจะเป็นกรณีที่พบบ่อยที่สุดจนกระทั่งใน Chrome 80 เราได้ส่ง สำหรับสถาปัตยกรรม 64- บิตซึ่งจำเป็นต้องลดขนาด Smi ให้เหลือ 31 บิตซึ่งเป็นที่รู้จักจากแพลตฟอร์ม 32 บิต หากคุณบังเอิญมีการใช้งานตามข้อสันนิษฐานว่าโดยทั่วไปแล้ว Smis เป็น 32 บิตคุณจะได้รับสถานการณ์ที่โชคร้ายเช่นนี้นี้
โชคดีที่คุณจดบันทึกไว้อาร์เรย์สองตัวยังคงเร็วมาก สำหรับโค้ดที่เป็นตัวเลขหนักอาจเป็นไปได้ที่จะสมมติ / กำหนดเป้าหมายอาร์เรย์คู่ เมื่อพิจารณาจากความชุกของ doubles ใน JavaScript จึงมีเหตุผลที่จะสมมติว่าเอ็นจิ้นทั้งหมดมีการสนับสนุนที่ดีสำหรับ doubles และ double array
เป็นไปได้ที่จะทำการเขียนโปรแกรมทั่วไปที่มีประสิทธิภาพสูงใน Javascript โดยไม่ต้องใช้อะไรเช่นระบบมาโครในการอินไลน์สิ่งต่าง ๆ เช่น vec.add () ลงใน callsites?
"ทั่วไป" มักจะขัดแย้งกับ "ประสิทธิภาพสูง" สิ่งนี้ไม่เกี่ยวข้องกับ JavaScript หรือการปรับใช้เครื่องมือเฉพาะ
รหัส "ทั่วไป" หมายความว่าต้องทำการตัดสินใจในขณะใช้งานจริง ทุกครั้งที่คุณเรียกใช้ฟังก์ชันรหัสต้องเรียกใช้เพื่อระบุว่า "เป็นx
จำนวนเต็มหรือไม่ถ้าเป็นเช่นนั้นให้พา ธ โค้ดนั้นx
เป็นสตริงหรือไม่แล้วข้ามไปที่นี่มันเป็นวัตถุหรือไม่.valueOf
ไม่มีหรือไม่จากนั้น อาจเป็นไปได้ว่า.toString()
อาจใช้โซ่ต้นแบบของมันเรียกมันและเริ่มใหม่ตั้งแต่ต้นด้วยผลลัพธ์ " รหัสที่ได้รับการปรับปรุงประสิทธิภาพ "ประสิทธิภาพสูง" นั้นสร้างขึ้นจากแนวคิดที่จะลดการตรวจสอบแบบไดนามิกทั้งหมด เป็นไปได้ก็ต่อเมื่อเอ็นจิ้น / คอมไพเลอร์มีวิธีอนุมานชนิดล่วงหน้า: หากสามารถพิสูจน์ (หรือสมมติว่ามีความน่าจะx
เป็นสูงพอ) ที่จะเป็นจำนวนเต็มเสมอมันจะต้องสร้างรหัสสำหรับกรณีนั้นเท่านั้น ( เตรียมพร้อมโดยการตรวจสอบประเภทหากข้อสันนิษฐานที่ไม่ได้มีส่วนเกี่ยวข้อง)
การฝังเป็นมุมฉากทั้งหมดนี้ ฟังก์ชั่น "ทั่วไป" ยังสามารถรับการ inline ในบางกรณีคอมไพเลอร์อาจเผยแพร่ข้อมูลชนิดลงในฟังก์ชัน inlined เพื่อลดความหลากหลายที่มี
(สำหรับการเปรียบเทียบ: C ++ เป็นภาษาที่รวบรวมแบบสแตติกมีเทมเพลตเพื่อแก้ไขปัญหาที่เกี่ยวข้องในระยะสั้นพวกเขาปล่อยให้โปรแกรมเมอร์สั่งให้คอมไพเลอร์สร้างสำเนาเฉพาะของฟังก์ชัน (หรือคลาสทั้งหมด) โดยเฉพาะอย่างยิ่ง วิธีแก้ปัญหาที่ดีสำหรับบางกรณี แต่ไม่ใช่หากไม่มีชุดข้อเสียของตัวเองเช่นเวลาในการรวบรวมที่ยาวนานและไบนารีขนาดใหญ่แน่นอนว่า JavaScript ไม่มีเทมเพลตเช่นนี้คุณสามารถใช้eval
เพื่อสร้างระบบที่ค่อนข้างคล้ายกัน ทำงานในข้อเสียที่คล้ายกัน: คุณจะต้องทำงานเทียบเท่ากับคอมไพเลอร์ของ C ++ ที่รันไทม์และคุณต้องกังวลเกี่ยวกับจำนวนโค้ดที่คุณสร้างขึ้น)
รหัสประสิทธิภาพสูงแบบแยกส่วนได้กลายเป็น libaries ในแง่ของสิ่งต่าง ๆ เช่นไซต์โทร megamorphic และ deoptimisations ได้อย่างไร ตัวอย่างเช่นถ้าฉันมีความสุขที่ใช้แพ็คเกจพีชคณิตเชิงเส้น A ที่ความเร็วสูงและจากนั้นฉันนำเข้าแพ็คเกจ B ที่ขึ้นอยู่กับ A แต่ B เรียกมันด้วยประเภทอื่น ๆ และ deoptimises มันในทันใด (โดยไม่ต้องเปลี่ยนรหัสของฉัน) รหัสของฉันทำงานช้า .
ใช่นั่นเป็นปัญหาทั่วไปของ JavaScript V8 เคยใช้ builtins บางอย่าง (คล้าย ๆArray.sort
) ใน JavaScript ภายในและปัญหานี้ (ที่เราเรียกว่า "ความคิดเห็นเกี่ยวกับการตอบรับพิมพ์") เป็นหนึ่งในสาเหตุหลักที่ทำไมเราจึงย้ายออกจากเทคนิคนั้นโดยสิ้นเชิง
ที่กล่าวว่าสำหรับรหัสตัวเลขนั้นมีไม่กี่ประเภท (เฉพาะ Smis และ double) และตามที่คุณตั้งข้อสังเกตว่าพวกเขาควรจะมีประสิทธิภาพที่คล้ายกันในทางปฏิบัติดังนั้นในขณะที่มลพิษจากข้อเสนอแนะนั้นเป็นข้อกังวลทางทฤษฎีและในบางกรณี มีผลกระทบอย่างมีนัยสำคัญและเป็นไปได้อย่างมากว่าในสถานการณ์พีชคณิตเชิงเส้นคุณจะไม่เห็นความแตกต่างที่วัดได้
นอกจากนี้ภายในเครื่องยนต์ยังมีสถานการณ์อีกมากมายที่นอกเหนือจาก "หนึ่งประเภท == เร็ว" และ "มากกว่าหนึ่งประเภท == ช้า" หากการดำเนินการที่กำหนดได้เห็นทั้ง Smis และ doubles แล้วนั่นถือว่าใช้ได้ทั้งหมด การโหลดองค์ประกอบจากอาร์เรย์สองชนิดนั้นก็ดีเช่นกัน เราใช้คำว่า "megamorphic" สำหรับสถานการณ์เมื่อการโหลดได้เห็นประเภทที่แตกต่างกันมากมายที่มีให้ในการติดตามพวกเขาทีละรายการและใช้กลไกทั่วไปมากกว่าที่ปรับขนาดได้ดีกว่าประเภทจำนวนมาก - ฟังก์ชันที่มีโหลดดังกล่าวสามารถ ยังคงได้รับการเพิ่มประสิทธิภาพ "deoptimization" เป็นการกระทำที่เฉพาะเจาะจงในการทิ้งโค้ดที่ปรับให้เหมาะสมที่สุดสำหรับฟังก์ชั่นเพราะรูปแบบใหม่จะเห็นว่ายังไม่เคยเห็นมาก่อนและดังนั้นรหัสที่ปรับให้เหมาะสมจึงไม่พร้อมที่จะจัดการ แต่ถึงกระนั้นก็ดี เพียงกลับไปที่รหัสที่ไม่ได้เพิ่มประสิทธิภาพเพื่อรวบรวมคำติชมที่พิมพ์มากขึ้นและเพิ่มประสิทธิภาพอีกครั้งในภายหลัง หากเกิดขึ้นสองสามครั้งก็ไม่มีอะไรต้องกังวล มันจะกลายเป็นปัญหาในกรณีที่ไม่ดีทางพยาธิวิทยา
ดังนั้นบทสรุปของทั้งหมดที่คือไม่ต้องกังวลเกี่ยวกับเรื่องนี้ เพียงแค่เขียนรหัสที่สมเหตุสมผลให้เอ็นจิ้นจัดการกับมัน และโดย "สมเหตุสมผล" ฉันหมายถึง: สิ่งที่เหมาะสมสำหรับกรณีการใช้งานของคุณคือสามารถอ่านได้บำรุงรักษาใช้อัลกอริธึมที่มีประสิทธิภาพไม่มีข้อบกพร่องเช่นการอ่านเกินความยาวของอาร์เรย์ เป็นการดีที่นั่นคือทั้งหมดที่มีให้และคุณไม่จำเป็นต้องทำอะไรอีก ถ้ามันทำให้คุณรู้สึกดีขึ้นที่จะทำอะไรบางอย่างและ / หรือถ้าคุณสังเกตปัญหาการปฏิบัติจริง ๆ ฉันสามารถเสนอแนวคิดสองอย่าง:
การใช้ TypeScript สามารถช่วยได้ คำเตือนไขมันใหญ่: ประเภทของ TypeScript นั้นมุ่งเน้นไปที่ประสิทธิภาพของนักพัฒนาไม่ใช่ประสิทธิภาพการดำเนินการ (และเมื่อปรากฎออกมามุมมองทั้งสองนั้นมีความต้องการที่แตกต่างกันมากจากระบบประเภท) ที่กล่าวว่ามีบางส่วนที่ทับซ้อนกัน: เช่นถ้าคุณใส่คำอธิบายประกอบอย่างสม่ำเสมอเช่นnumber
นั้นคอมไพเลอร์ TS จะเตือนคุณถ้าคุณตั้งใจใส่null
อาเรย์หรือฟังก์ชั่นที่ควรจะมี / ทำงานกับตัวเลขเท่านั้น แน่นอนว่าจำเป็นต้องมีการลงโทษทางวินัย: number_func(random_object as number)
ช่องหนีเดี่ยวสามารถทำลายทุกอย่างได้อย่างเงียบ ๆ เพราะความถูกต้องของคำอธิบายประกอบประเภทไม่ได้บังคับใช้ที่ใดก็ได้
การใช้ TypedArrays สามารถช่วยได้เช่นกัน พวกเขามีค่าใช้จ่ายเพิ่มเติมเล็กน้อย (ปริมาณการใช้หน่วยความจำและความเร็วในการจัดสรร) ต่ออาร์เรย์เมื่อเทียบกับอาร์เรย์ JavaScript ปกติ (ดังนั้นหากคุณต้องการอาร์เรย์ขนาดเล็กจำนวนมากดังนั้นอาร์เรย์ปกติอาจมีประสิทธิภาพมากกว่า) และยืดหยุ่นน้อยกว่าเพราะไม่สามารถเติบโตได้ หรือลดขนาดหลังจากการจัดสรร แต่ให้การรับประกันว่าองค์ประกอบทั้งหมดมีประเภทเดียว
มีเครื่องมือวัดที่ใช้งานง่ายสำหรับตรวจสอบสิ่งที่เอ็นจิน Javascript ทำงานภายในกับชนิดหรือไม่?
ไม่และนั่นเป็นความตั้งใจ ตามที่อธิบายไว้ข้างต้นเราไม่ต้องการให้คุณปรับแต่งโค้ดของคุณตามรูปแบบใด ๆ ที่ V8 สามารถเพิ่มประสิทธิภาพได้ดีเป็นพิเศษในวันนี้และเราไม่เชื่อว่าคุณต้องการทำเช่นนั้น ชุดของสิ่งต่าง ๆ สามารถเปลี่ยนแปลงได้ในทิศทางใดทิศทางหนึ่ง: หากมีรูปแบบที่คุณชอบใช้เราอาจปรับให้เหมาะสมสำหรับรุ่นในอนาคต (ก่อนหน้านี้เราเคยคิดที่จะเก็บจำนวนเต็ม 32 บิตที่ไม่มีกล่องเป็นองค์ประกอบ . แต่ทำงานที่ยังไม่ได้เริ่มดังนั้นจึงไม่มีสัญญา) และบางครั้งหากมีรูปแบบที่เราเคยใช้ในการปรับให้เหมาะสมในอดีตเราอาจตัดสินใจที่จะวางสิ่งนั้นลงหากมันได้รับในทางอื่นการเพิ่มประสิทธิภาพที่สำคัญ / มีผลกระทบมากกว่า นอกจากนี้การทำฮิวริสติกแบบอินไลน์ก็ยากที่จะทำให้ถูกต้อง ดังนั้นการตัดสินใจที่ถูกต้องในเวลาที่เหมาะสมคือพื้นที่ของการวิจัยอย่างต่อเนื่องและการเปลี่ยนแปลงที่สอดคล้องกับพฤติกรรมของเครื่องยนต์ / คอมไพเลอร์ ซึ่งทำให้เป็นอีกกรณีหนึ่งที่ทุกคนจะโชคร้าย (คุณและเรา) หากคุณใช้เวลามากในการปรับแต่งรหัสของคุณจนกว่าชุดของเบราว์เซอร์รุ่นปัจจุบันบางรุ่นจะทำการตัดสินใจโดยประมาณที่คุณคิดว่า (หรือรู้หรือไม่?) จะดีที่สุดเพียงกลับมาอีกครึ่งปีต่อมา เปลี่ยนฮิวริสติกของพวกเขาแล้ว
แน่นอนว่าคุณสามารถวัดประสิทธิภาพการทำงานของแอปพลิเคชันของคุณโดยรวมได้ - นั่นคือสิ่งที่สำคัญที่สุดไม่ใช่ตัวเลือกที่เครื่องมือสร้างขึ้นภายในโดยเฉพาะ ระวัง microbenchmarks เพราะมันทำให้เข้าใจผิด: หากคุณแยกโค้ดสองบรรทัดและเกณฑ์มาตรฐานเท่านั้นโอกาสก็คือว่าสถานการณ์จะแตกต่างกันพอสมควร (เช่นข้อเสนอแนะประเภทต่าง ๆ ) ที่เอ็นจิ้นจะทำการตัดสินใจแตกต่างกันมาก