यहां V8 डेवलपर। इस प्रश्न में रुचि की मात्रा, और अन्य उत्तरों की कमी को देखते हुए, मैं इसे एक शॉट दे सकता हूं; मुझे डर है कि यह वह उत्तर नहीं होगा, जिसकी आप उम्मीद कर रहे थे।
क्या पैक्ड SMI सरणियों (उदाहरण के लिए) की दुनिया में रहते हुए प्रोग्राम करने के तरीके पर कहीं दिशा-निर्देशों का एक सेट है?
संक्षिप्त उत्तर: यह यहीं है const guidelines = ["keep your integers small enough"]
:।
लंबा उत्तर: दिशानिर्देशों का एक व्यापक सेट देना विभिन्न कारणों से मुश्किल है। सामान्य तौर पर, हमारी राय यह है कि जावास्क्रिप्ट डेवलपर्स को कोड लिखना चाहिए जो उन्हें और उनके उपयोग के मामले में समझ में आता है, और जावास्क्रिप्ट इंजन डेवलपर्स को यह पता लगाना चाहिए कि उस कोड को अपने इंजन पर तेजी से कैसे चलाया जाए। दूसरी तरफ, स्पष्ट रूप से उस आदर्श की कुछ सीमाएँ हैं, इस अर्थ में कि कुछ कोडिंग पैटर्न हमेशा दूसरों की तुलना में उच्च निष्पादन लागत होंगे, इंजन कार्यान्वयन विकल्पों और अनुकूलन प्रयासों की परवाह किए बिना।
जब हम प्रदर्शन सलाह के बारे में बात करते हैं, तो हम इसे ध्यान में रखने की कोशिश करते हैं, और सावधानीपूर्वक अनुमान लगाते हैं कि क्या सिफारिशों में कई इंजनों और कई वर्षों में शेष रहने की उच्च संभावना है, और यह भी उचित रूप से मुहावरेदार / गैर-घुसपैठ है।
उदाहरण के लिए हाथ में वापस आना: आंतरिक रूप से Smis का उपयोग करना एक कार्यान्वयन विवरण माना जाता है जिसके बारे में उपयोगकर्ता कोड को जानने की आवश्यकता नहीं है। यह कुछ मामलों को अधिक कुशल बना देगा, और अन्य मामलों में चोट नहीं पहुंचनी चाहिए। सभी इंजन Smis का उपयोग नहीं करते हैं (उदाहरण के लिए, AFAIK Firefox / Spidermonkey ऐतिहासिक रूप से नहीं; मैंने सुना है कि कुछ मामलों में वे इन दिनों Smis का उपयोग करते हैं; लेकिन मैं कोई विवरण नहीं जानता और किसी भी प्राधिकरण के साथ बात नहीं कर सकता। मामला)। V8 में, Smis का आकार एक आंतरिक विवरण है, और वास्तव में समय और संस्करणों के साथ बदल रहा है। 32-बिट प्लेटफ़ॉर्म पर, जो बहुसंख्यक उपयोग का मामला हुआ करता था, Smis हमेशा 31-बिट हस्ताक्षरित पूर्णांक रहा है; 64-बिट प्लेटफ़ॉर्म पर वे 32-बिट हस्ताक्षरित पूर्णांक हुआ करते थे, जो हाल ही में सबसे आम मामले की तरह लग रहा था, जब तक कि क्रोम 80 में हमने "पॉइंटर कंप्रेशन" को भेज दिया 64-बिट आर्किटेक्चर के लिए, जिसे 32-बिट प्लेटफ़ॉर्म से ज्ञात 31 बिट्स के लिए स्माइ साइज़ कम करने की आवश्यकता थी। यदि आप ऐसा मानते हैं कि Smis आमतौर पर 32 बिट्स हैं, तो इस तरह के दुर्भाग्यपूर्ण स्थितियों को प्राप्त करने के आधार पर एक कार्यान्वयन हुआ हैयह ।
शुक्र है, जैसा कि आपने उल्लेख किया, दोहरे सरणियाँ अभी भी बहुत तेज़ हैं। संख्या-भारी कोड के लिए, यह संभवतः दोहरे सरणियों को मानने / लक्षित करने के लिए समझ में आता है। जावास्क्रिप्ट में युगल की व्यापकता को देखते हुए, यह मानना उचित है कि सभी इंजनों को युगल और दोहरे सरणियों के लिए अच्छा समर्थन है।
जावास्क्रिप्ट में जेनेस्क्रिप्ट में जेनेरिक हाई-परफॉर्मेंस प्रोग्रामिंग को बिना किसी मैक्रो सिस्टम की तरह इस्तेमाल करना संभव है?
"जेनेरिक" आम तौर पर "उच्च प्रदर्शन" के साथ बाधाओं पर होता है। यह जावास्क्रिप्ट, या विशिष्ट इंजन कार्यान्वयन के लिए असंबंधित है।
"जेनेरिक" कोड का मतलब है कि निर्णय रनटाइम पर किए जाने हैं। हर बार जब आप किसी फ़ंक्शन को निष्पादित करते हैं, तो कोड निर्धारित करने के लिए चलना होता है, कहते हैं, " x
एक पूर्णांक है? यदि हां, तो उस कोड पथ को ले जाएं। क्या x
एक स्ट्रिंग है? फिर यहां पर कूदें। क्या यह एक वस्तु है? क्या यह है .valueOf
? नहीं? तब? हो सकता है .toString()
? हो सकता है कि इसकी प्रोटोटाइप श्रृंखला पर? कॉल करें, और इसके परिणाम के साथ शुरुआत से पुनरारंभ करें "। "उच्च प्रदर्शन" अनुकूलित कोड अनिवार्य रूप से इन सभी गतिशील चेक को छोड़ने के विचार पर बनाया गया है; यह तभी संभव है जब इंजन / कंपाइलर के पास समय से पहले टाइप करने का कोई तरीका हो: यदि यह साबित हो सकता है (या उच्च पर्याप्त संभावना के साथ) जो x
हमेशा पूर्णांक होने वाला है, तो उसे केवल उस स्थिति के लिए कोड उत्पन्न करना होगा ( एक प्रकार की जांच द्वारा संरक्षित अगर अप्रमाणित धारणाओं में शामिल थे)।
इनलाइनिंग ऑर्थोगोनल है इस सब के लिए। एक "जेनेरिक" फ़ंक्शन अभी भी मिल सकता है। कुछ मामलों में, कंपाइलर वहाँ बहुरूपता को कम करने के लिए इनबिल्ड फ़ंक्शन में टाइप जानकारी का प्रचार करने में सक्षम हो सकता है।
(तुलना के लिए: सी ++, एक संकलित भाषा होने के नाते, संबंधित समस्या को हल करने के लिए टेम्प्लेट हैं। संक्षेप में, उन्होंने प्रोग्रामर को स्पष्ट रूप से कंपाइलरों को निर्देश दिया है कि वे फंक्शंस की विशेष प्रतियों (या संपूर्ण कक्षाओं) को बनाएं, जो दिए गए प्रकारों पर मानकीकृत हैं। कुछ मामलों के लिए अच्छा समाधान, लेकिन कमियों के अपने स्वयं के सेट के बिना नहीं, उदाहरण के लिए लंबे संकलन समय और बड़े बिनर्स। जावास्क्रिप्ट, निश्चित रूप से, टेम्पलेट जैसी कोई चीज नहीं है। आप eval
एक प्रणाली का निर्माण करने के लिए उपयोग कर सकते हैं जो कुछ हद तक समान है, लेकिन फिर आप। 'समान कमियों में चलते हैं: आपको रन टाइम में C ++ कंपाइलर के काम के बराबर काम करना होगा, और आपको कोड की भारी मात्रा के बारे में चिंता करनी होगी।'
मेगामॉर्फिक कॉल साइट्स और डिओप्टीमाइजेशन जैसी चीजों के प्रकाश में एक उच्च प्रदर्शन कोड को कैसे कामेच्छा में बदल देता है? उदाहरण के लिए, अगर मैं उच्च गति पर रैखिक बीजगणित पैकेज ए का उपयोग खुशी से कर रहा हूं, और फिर मैं एक पैकेज बी का आयात करता हूं जो ए पर निर्भर करता है, लेकिन बी इसे अन्य प्रकारों के साथ कॉल करता है और इसे बंद कर देता है, अचानक (मेरा कोड बदले बिना) मेरा कोड धीमी हो जाता है ।
हां, यह जावास्क्रिप्ट के साथ एक सामान्य समस्या है। V8 Array.sort
आंतरिक रूप से जावास्क्रिप्ट में कुछ अंतर्निहित (जैसे चीजों ) को लागू करने के लिए उपयोग किया जाता है , और यह समस्या (जिसे हम "टाइप प्रतिक्रिया प्रदूषण" कहते हैं) प्राथमिक कारणों में से एक था कि हम पूरी तरह से उस तकनीक से दूर क्यों चले गए हैं।
उस ने कहा, संख्यात्मक कोड के लिए, वे सभी प्रकार नहीं हैं (केवल स्माइली और डबल्स), और जैसा कि आपने उल्लेख किया है कि उन्हें अभ्यास में समान प्रदर्शन होना चाहिए, इसलिए जबकि टाइप प्रतिक्रिया प्रदूषण वास्तव में एक सैद्धांतिक चिंता है, और कुछ मामलों में हो सकता है महत्वपूर्ण प्रभाव पड़ता है, यह भी काफी संभावना है कि रैखिक बीजगणित परिदृश्यों में आप एक औसत दर्जे का अंतर नहीं देखेंगे।
इसके अलावा, इंजन के अंदर "एक प्रकार == तेज" और "एक से अधिक प्रकार == धीमे" की तुलना में कई और स्थितियां हैं। यदि किसी दिए गए ऑपरेशन में स्मिस और डबल्स दोनों देखे गए हैं, तो यह पूरी तरह से ठीक है। दो प्रकार के सरणियों से लोडिंग तत्व भी ठीक है। हम "मेगामोर्फिक" शब्द का उपयोग उस स्थिति के लिए करते हैं जब किसी लोड ने इतने अलग-अलग प्रकार देखे हैं कि इसे व्यक्तिगत रूप से ट्रैक करने पर छोड़ दिया जाता है और इसके बजाय अधिक सामान्य तंत्र का उपयोग करता है जो बड़ी संख्या में बेहतर तरीके से स्केल करता है - एक फ़ंक्शन जिसमें ऐसे लोड हो सकते हैं। अभी भी अनुकूलित करें। एक "deoptimization" एक फ़ंक्शन के लिए अनुकूलित कोड को फेंकने के लिए एक बहुत ही विशिष्ट कार्य है क्योंकि एक नया प्रकार देखा जाता है जिसे पहले नहीं देखा गया है, और इसलिए कि अनुकूलित कोड संभाल करने के लिए सुसज्जित नहीं है। लेकिन यह भी ठीक है: बस अधिक प्रकार की प्रतिक्रिया एकत्र करने के लिए अडॉप्ट किए गए कोड पर वापस जाएं, और बाद में फिर से ऑप्टिमाइज़ करें। अगर यह एक दो बार होता है, तो यह चिंता की कोई बात नहीं है; यह केवल विकृति के खराब मामलों में एक समस्या बन जाता है।
तो सब का सारांश यह है: इसके बारे में चिंता मत करो । बस उचित कोड लिखें, इंजन को इससे निपटने दें। और "उचित" से मेरा मतलब है: आपके उपयोग के मामले के लिए क्या मायने रखता है, पठनीय है, बनाए रखने योग्य है, कुशल एल्गोरिदम का उपयोग करता है, इसमें सरणियों की लंबाई से परे पढ़ने जैसे कीड़े शामिल नहीं हैं। आदर्श रूप से, यही सब कुछ है, और आपको कुछ और करने की आवश्यकता नहीं है। यदि यह आपको कुछ करने के लिए बेहतर महसूस करता है , और / या यदि आप वास्तव में प्रदर्शन मुद्दों को देख रहे हैं, तो मैं दो विचार प्रस्तुत कर सकता हूं:
टाइपस्क्रिप्ट का उपयोग करने से मदद मिल सकती है। बड़ी वसा चेतावनी: टाइपस्क्रिप्ट के प्रकार डेवलपर उत्पादकता पर लक्षित होते हैं, निष्पादन निष्पादन नहीं (और जैसा कि यह पता चलता है, उन दो दृष्टिकोणों में एक प्रकार की प्रणाली से बहुत अलग आवश्यकताएं हैं)। उस ने कहा, कुछ ओवरलैप है: जैसे यदि आप लगातार चीजों को एनोटेट करते हैं number
, तो टीएस कंपाइलर आपको चेतावनी देगा यदि आप गलती null
से एक सरणी या फ़ंक्शन में डालते हैं जो केवल संख्याओं पर होता है / संचालित होता है। बेशक, अनुशासन अभी भी आवश्यक है: एक एकल number_func(random_object as number)
एस्केप हैच चुपचाप सब कुछ कम कर सकता है, क्योंकि प्रकार एनोटेशन की शुद्धता कहीं भी लागू नहीं होती है।
TypedArrays का उपयोग करने से भी मदद मिल सकती है। नियमित जावास्क्रिप्ट सरणियों की तुलना में उनके पास थोड़ी अधिक ओवरहेड (मेमोरी खपत और आवंटन की गति) है (इसलिए यदि आपको कई छोटे सरणियों की आवश्यकता है, तो नियमित सरणियां संभवतः अधिक कुशल हैं), और वे कम लचीले हैं क्योंकि वे नहीं बढ़ सकते हैं या आवंटन के बाद सिकुड़ते हैं, लेकिन वे गारंटी प्रदान करते हैं कि सभी तत्वों में एक प्रकार होता है।
क्या किसी भी प्रकार के साथ जावास्क्रिप्ट इंजन आंतरिक रूप से क्या कर रहा है, यह जांचने के लिए माप उपकरणों का उपयोग करना आसान है?
नहीं, और यह जानबूझकर है। जैसा कि ऊपर बताया गया है, हम नहीं चाहते हैं कि आप अपने कोड को विशेष रूप से अच्छी तरह से आज के रूप में अच्छी तरह से अनुकूलित कर सकते हैं जो V8 को अनुकूलित कर सकते हैं, और हमें विश्वास नहीं है कि आप वास्तव में ऐसा करना चाहते हैं। चीजों का वह सेट दोनों दिशाओं में बदल सकता है: यदि कोई पैटर्न है जिसे आप उपयोग करना पसंद करेंगे, तो हम भविष्य के संस्करण में इसके लिए अनुकूलन कर सकते हैं (हम पहले 32-बिट पूर्णांक को स्टोर करने वाले तत्वों के रूप में संग्रहीत करने के विचार के साथ आए हैं।) ; लेकिन उस पर काम अभी तक शुरू नहीं हुआ है, इसलिए कोई वादा नहीं करता है); और कभी-कभी अगर कोई ऐसा पैटर्न होता है जिसका उपयोग हम अतीत में अनुकूलन के लिए करते हैं, तो हम यह छोड़ने का फैसला कर सकते हैं कि यदि यह अन्य, अधिक महत्वपूर्ण / प्रभावशाली अनुकूलन के रास्ते में आता है। इसके अलावा, उत्तराधिकार को प्राप्त करने के लिए विषमताओं को दूर करना जैसी चीजें बेहद कठिन हैं, इसलिए सही समय पर सही इनलाइनिंग निर्णय करना चल रहे अनुसंधान और इंजन / कंपाइलर व्यवहार के अनुरूप परिवर्तन का एक क्षेत्र है; जो इसे एक और मामला बनाता है जहां यह सभी के लिए दुर्भाग्यपूर्ण होगा (आपऔर यदि आप वर्तमान ब्राउज़र संस्करणों के कुछ सेट आप सोचते हैं (या पता है) के बारे में कुछ tolining निर्णय करता है जब तक आप अपने कोड tweaking का एक बहुत समय बिताया है, केवल सबसे अच्छा कर रहे हैं, तो केवल आधे साल बाद फिर से महसूस करने के लिए कि वर्तमान ब्राउज़र अपने उत्तराधिकारियों को बदल दिया है।
आप निश्चित रूप से, हमेशा एक पूरे के रूप में अपने आवेदन के प्रदर्शन को माप सकते हैं - यही आखिरकार मायने रखता है, न कि क्या विकल्प विशेष रूप से आंतरिक रूप से बनाया गया इंजन। माइक्रोबेन्चमार्क से सावधान रहें, क्योंकि वे भ्रामक हैं: यदि आप केवल कोड और बेंचमार्क की दो लाइनें निकालते हैं, तो संभावना है कि परिदृश्य पर्याप्त रूप से भिन्न होगा (उदाहरण के लिए, विभिन्न प्रकार की प्रतिक्रिया) जो इंजन बहुत अलग निर्णय लेंगे।