सरल बनाम जटिल (लेकिन प्रदर्शन कुशल) समाधान - किसे चुनना है और कब?


28

मैं कुछ वर्षों से प्रोग्रामिंग कर रहा हूं और अक्सर खुद को दुविधा में पाता हूं।

इसके दो उपाय हैं -

  • एक सरल एक है यानी सरल दृष्टिकोण, समझने और बनाए रखने में आसान। इसमें कुछ अतिरेक, कुछ अतिरिक्त कार्य (अतिरिक्त आईओ, अतिरिक्त प्रसंस्करण) शामिल हैं और इसलिए यह सबसे इष्टतम समाधान नहीं है।
  • लेकिन अन्य एक जटिल दृष्टिकोण का उपयोग करता है, जिसे लागू करना मुश्किल है, अक्सर बहुत सारे मॉड्यूल के बीच सहभागिता शामिल है और एक प्रदर्शन कुशल समाधान है।

जब मुझे कठिन प्रदर्शन SLA को पूरा करने के लिए नहीं करना चाहिए, तो मुझे किस समाधान के लिए प्रयास करना चाहिए और यहां तक ​​कि सरल समाधान प्रदर्शन SLA को पूरा कर सकता है? मैंने सरल समाधान के लिए अपने साथी डेवलपर्स के बीच तिरस्कार महसूस किया है।

यदि आपके प्रदर्शन SLA को सरल समाधान से पूरा किया जा सकता है, तो सबसे इष्टतम जटिल समाधान के साथ आना अच्छा है?


10
देखें: मैं "डेवलपर के बुरे अनुकूलन अंतर्ज्ञान" से कैसे बचूँ? "दुर्भाग्य से, आमतौर पर डेवलपर्स में भयानक अंतर्ज्ञान होता है, जहां एक आवेदन में प्रदर्शन की समस्याएं वास्तव में होंगी ...."
gnat

1
क्या "सबसे इष्टतम" अभी भी "अच्छा पर्याप्त" नहीं होगा? फिर उसी के साथ रहो।

8
हां। " ले मिक्स इस्ट ले'नेमी डू बिएन। " वोल्टेयर। ("परफेक्ट अच्छे का दुश्मन है।") अच्छा पर्याप्त पर्याप्त है - जब तक कि प्रदर्शन परीक्षण अन्यथा न कहे।
डेविड हामेन

मुझे लगता है कि (सामान्य रूप से) सरल का तात्पर्य कुशल है। इसलिए अक्सर समझौता करने की आवश्यकता नहीं होती है।
दान

2
"ऐसा लगता है नहीं है जब वहाँ जोड़ने के लिए ज्यादा कुछ नहीं है कि पूर्णता प्राप्त कर ली है, लेकिन जब वहाँ दूर करने के लिए ज्यादा कुछ नहीं है।" - एंटोनी डे सेंट-एक्सुपेरी
keuleJ

जवाबों:


58

जब मुझे कठिन प्रदर्शन SLA को पूरा करने के लिए नहीं करना चाहिए, तो मुझे किस समाधान के लिए प्रयास करना चाहिए और यहां तक ​​कि सरल समाधान प्रदर्शन SLA को पूरा कर सकता है?

सरल एक। यह कल्पना को पूरा करता है, यह समझना आसान है, इसे बनाए रखना आसान है, और यह शायद बहुत कम छोटी गाड़ी है।

प्रदर्शन कुशल समाधान की वकालत करने में आप जो कर रहे हैं, वह आपके कोड में सट्टा सामान्यता और समय से पहले अनुकूलन का परिचय दे रहा है। यह मत करो! प्रदर्शन हर दूसरे सॉफ्टवेयर इंजीनियरिंग 'इलिटी' के बारे में सिर्फ अनाज के खिलाफ जाता है (विश्वसनीयता, स्थिरता, पठनीयता, परीक्षणशीलता, समझ, ...)। परीक्षण के दौरान चेस का प्रदर्शन बताता है कि प्रदर्शन के बाद सही मायने में पीछा करने की जरूरत है।

जब प्रदर्शन से कोई फर्क नहीं पड़ता तो प्रदर्शन का पीछा न करें। यहां तक ​​कि अगर यह कोई फर्क नहीं पड़ता है, तो आपको केवल उन क्षेत्रों में प्रदर्शन का पीछा करना चाहिए जहां परीक्षण इंगित करता है कि एक प्रदर्शन अड़चन मौजूद है। प्रदर्शन समस्याओं को simple_but_slow_method_to_do_X()तेज संस्करण के साथ बदलने का बहाना न बनने दें यदि वह सरल संस्करण एक अड़चन के रूप में नहीं दिखता है।

एन्हांस्ड प्रदर्शन कोड गंध समस्याओं के एक मेजबान के साथ लगभग अनिवार्य रूप से संलग्न है। आपने प्रश्न में कई का उल्लेख किया है: एक जटिल दृष्टिकोण, जिसे लागू करना मुश्किल है, उच्च युग्मन। क्या वे वास्तव में घसीटने लायक हैं?


आपका जवाब बहुत मददगार है
MoveFast

1
जितना संभव हो उतना सरल, लेकिन सरल नहीं; जितना संभव हो उतना तेज़, लेकिन तेज़ नहीं; आदि
user606723

2
"जब संदेह में, जानवर बल का उपयोग करें";)
टेम्डमर्स

कोड में टिप्पणियाँ यहाँ दोनों कैथैरिक और सहायक हो सकती हैं। कॉम्प्लेक्स + फास्ट सॉल्यूशन को इंगित करने वाली एक छोटी टिप्पणी, और आपने इसका उपयोग क्यों नहीं किया, यह आपको कम महसूस करवा सकता है जैसे आपने इष्टतम एल्गोरिथ्म को अनदेखा कर दिया। और यह अनुरक्षकों को आपकी पसंद को समझने में मदद कर सकता है और उन्हें सही दिशा में इंगित कर सकता है यदि अनुकूलन वास्तव में बाद में आवश्यक है।
TheAtomicOption

12

लघु उत्तर: जटिल से अधिक सरल समाधान को प्राथमिकता दें, और याद KISS और YAGNI सिद्धांतों

क्योंकि प्रारंभिक परियोजना आवश्यकताएं और सॉफ्टवेयर कभी भी परिपूर्ण नहीं होते हैं, इसके लिए परिवर्तनों की आवश्यकता होती है क्योंकि अनुप्रयोग विकसित / उपयोग किया जाता है। विकास के चरणों में Iterative दृष्टिकोण चीजों को सरल शुरू करने और आवश्यकतानुसार इसे विस्तारित करने के लिए एक बहुत अच्छा मैच है। सबसे सरल समाधान में लचीलेपन के लिए जगह है और बनाए रखने के लिए अधिक आसान है।

इसके अलावा, स्मार्ट बनने की कोशिश करना और अपने एप्लिकेशन का निर्माण करते समय कुछ ऐड-हॉक ऑप्टिमाइज़ेशन करना एक अच्छा अभ्यास नहीं है और इस समाधान को अधिक जटिल कर सकता है। जैसा कि ज्ञात है, "premature optimization is the root of all evil"- नुथ की पुस्तक से


1
@ManojGumber, कोई समस्या नहीं है और वास्तव में इसका सार जो हम प्रोग्रामर के रूप में करते हैं उसे पहली जगह पर ध्यान देना चाहिए।
ईएल यूसुबोव

8

यहां नथ से सबक लें: "हमें छोटी क्षमताओं के बारे में भूलना चाहिए, 97% समय के बारे में कहना चाहिए: समय से पहले अनुकूलन सभी बुराई की जड़ है"।

इस क्रम में अपने समाधान के बारे में सोचें: पहला, हमेशा, शुद्धता। दूसरा, स्पष्टता और सरलता में सुधार। तीसरा, और केवल तभी जब आप आवश्यकता, दक्षता प्रदर्शित कर सकते हैं।

दक्षता जोड़ना लगभग हमेशा आपके लिए कुछ महत्वपूर्ण होगा, और इसलिए केवल तभी पीछा किया जाना चाहिए जब आपको पता हो कि आपको आवश्यकता है।


4
ध्यान दें कि इसका मतलब यह नहीं है कि आपको पहले स्थान पर एक अच्छा कार्यान्वयन नहीं लिखना चाहिए।

@ ThorbjørnRavnAndersen: निश्चित रूप से, इसके बारे में पहले दो बिंदु हैं।
सिमोन

1
@simon बोली अक्सर एक विकल्प के रूप में प्रयोग किया जाता है

आपके दूसरे बिंदु के बारे में: मेरे पास एक सहकर्मी था जो अक्सर कहता था कि उसने सही स्पेगेटी से पहले गलत अच्छी तरह से संरचित और साफ कोड पसंद किया है।
बुहब

@ ThorbjørnRavnAndersen अक्षम लोग बहाने के लिए कुछ भी इस्तेमाल करेंगे। मूल विचार के मूल्य पर कोई प्रभाव नहीं पड़ता है।
सिमोन

7

सादगी विश्वसनीयता की शर्त है । यदि आपके पास एक सरल समाधान है जो काम करता है, तो हर तरह से इसके लिए जाएं! एक कार्यशील कार्यक्रम को अनुकूलित करने की तुलना में एक अनुकूलित कार्यक्रम काम करना बहुत आसान है। मूर के कानून के बारे में भी मत भूलना : यदि आपका सरल समाधान आज प्रदर्शन लक्ष्यों को पूरा करता है, तो यह संभवत: उन्हें एक या दो साल में 1 कुचल देगा ।


1 वहाँ कोई गारंटी नहीं है, क्योंकि जैसा कि जिमी हॉफ़ा ने अपनी टिप्पणी में उल्लेख किया है, मूर के कानून की अपनी सीमाएं हैं।


आप मूर के अन्य कानून के बारे में भूल गए, जिसमें कहा गया था, "उफ़, मेरे पहले कानून के बारे में .." क्षमा करें बॉस, मूर का कानून अब (दंडात्मक दंड) नहीं है। मैं आपकी बाकी बातों से असहमत नहीं हूं, मैं सिर्फ कम से कम कैविएट में ही रहूंगा जो कि पिछले हिस्से में था।
जिमी होफा

2
क्षमा करें, लेकिन इस उद्योग में मेरे सभी अनुभव में। "वर्क सेट" हमारे हार्डवेयर की गति की तुलना में तेजी से एफएआर बढ़ा रहे हैं, जो लगातार उन्नत है। वास्तव में, मैं सिर्फ मूर के कानून बिंदु को हटा दूंगा।
user606723

@ user606723 "वर्क सेट" बिंदु की वृद्धि "अनुकूलित या सरल" प्रश्न के लिए ऑर्थोगोनल है: कार्यभार उनके साथ पकड़ लेगा चाहे वे किस समाधान को लागू करें। मूर के कानून को मिश्रण में लाने की बात यह थी कि यदि लेखन के समय सरल समाधान कुछ प्रदर्शन दबाव में है, तो दबाव कम हो जाएगा क्योंकि तेजी से हार्डवेयर उपलब्ध हो जाएगा।
दासब्लिंकलाइटलाइट

@dasblinkenlight, कार्यस्थल की वृद्धि मूर के कानून की तुलना में प्रश्न के लिए कोई अधिक रूढ़िवादी नहीं है। कार्यपत्रक को समस्या में लाने की बात यह है कि यदि रिलीज़ के समय एक सरल समाधान कुछ प्रदर्शन दबाव में होता है, तो प्रदर्शन निकट भविष्य में बहुत ही अपर्याप्त होगा क्योंकि बढ़ते कार्यस्थल में सुधार हार्डवेयर द्वारा प्राप्त किसी भी प्रदर्शन में सुधार को ध्वस्त कर देता है। हालांकि मैं सरल, विश्वसनीय और बनाए रखने योग्य सॉफ़्टवेयर के लिए सभी हूं, सॉफ्टवेयर जारी करना जो पहले से ही रिलीज पर दबाव के दबाव में है और यहां तक ​​कि मूर के कानून की उम्मीद करना भी एक भयानक दर्शन है।
user606723

3

यदि आपके प्रदर्शन SLA को सरल समाधान से पूरा किया जा सकता है, तो सबसे इष्टतम जटिल समाधान के साथ आना अच्छा है?

इष्टतम एक अस्पष्ट शब्द है!

अंत में, अगर कॉम्प्लेक्स एक को बनाए रखने में बहुत जोखिम है, और अगर साधारण एक "अच्छा पर्याप्त" है, तो मैं हमेशा साधारण के पक्ष में गलत करूंगा।

परिसर में एक काफी अच्छा नहीं किया जा रहा की किसी भी जोखिम में जोड़ कर KISS शायद सही जवाब है।


2

मैं सरल एक पसंद करेंगे। मेरी राय में समय से पहले होने वाली अनुकूलन समस्याओं का उतना ही हल करते हैं जितना वे हल करते हैं। कई मामलों में अच्छा डिज़ाइन आपको भविष्य में दिए गए कार्यान्वयन को बदलने की अनुमति देता है, अगर वे अड़चन बन जाते हैं।

इसलिए नीचे की रेखा पर - मैं इसे जितना संभव हो उतना लचीला डिजाइन करूंगा, लेकिन लचीलेपन के लिए सादगी का त्याग नहीं करेगा।


2

किसकी कीमत कम?

ज्यादातर समय, एक सरल समाधान जो थोड़ा धीमा है, प्रदर्शन के मामले में पूरी तरह से स्वीकार्य होगा, और सादगी इसे विकसित करने, बनाए रखने और अंततः बदलने के लिए सस्ता बनाती है।

दूसरी ओर, कभी-कभी गति वास्तव में महत्वपूर्ण होती है, और वित्तीय लाभ जो कि छोटे गति के सुधार से होता है, एक अधिक जटिल समाधान की बढ़ी हुई लागत से कहीं अधिक हो सकता है। उदाहरण के लिए, लेनदेन को पूरा करने के लिए 0.01 से शेविंग करने से सिक्योरिटीज ट्रेडिंग सिस्टम बहुत अधिक लाभदायक हो सकता है। एक प्रणाली की दक्षता में 10% सुधार जो कई मिलियन उपयोगकर्ताओं का समर्थन करता है, का मतलब सर्वर की लागत में उल्लेखनीय कमी हो सकती है।

तो, जो सवाल आपको खुद से पूछना है वह यह है: क्या जटिल समाधान का उपयोग करने से इसकी अतिरिक्त लागत का भुगतान करने के लिए नीचे की रेखा पर पर्याप्त प्रभाव पड़ता है? वास्तव में, आपको अपने ग्राहक से यह तय करने के लिए कहना चाहिए कि वे बिल का भुगतान कर रहे हैं और संभावित लाभ प्राप्त कर रहे हैं। एक अच्छा विकल्प पहले सरल समाधान के साथ जाना है, और एक संभावित सुधार के रूप में अधिक जटिल समाधान प्रदान करना है। यह आपको अपने सिस्टम को चलाने और चलाने देता है और अपने क्लाइंट को परीक्षण शुरू करने के लिए कुछ देता है, और यह अनुभव अधिक जटिल समाधान को लागू करने (या लागू नहीं) करने के निर्णय को सूचित कर सकता है।


2

दो दृष्टिकोणों का मूल्यांकन करते समय, एक सरल लेकिन कम कुशल होता है जबकि अन्य अधिक जटिल और अधिक कुशल होने के कारण, किसी को समस्या और प्रोजेक्ट डोमेन पर विचार करना पड़ता है।

स्वास्थ्य सेवा उद्योग के लिए एक बहु-अरब सॉफ्टवेयर परियोजना पर विचार करें, जिसने 15 साल के रखरखाव और +20 वर्षों के उपयोग के लिए जीवनकाल की योजना बनाई है। ऐसी परियोजना में प्रदर्शन निश्चित रूप से चिंता का विषय नहीं होगा, लेकिन परियोजना की जटिलता और संरचना परियोजना के रखरखाव के लिए बड़ी समस्याएं पैदा कर सकती हैं, जो कि न्यूनतम 15 वर्षों तक रहता है। स्थिरता और सरलता किसी भी चीज से पहले आती है।

फिर, एक और उदाहरण पर विचार करें। एक कंसोल गेम इंजन जो अगले 5+ वर्षों के लिए कंपनी के आगामी खेलों को शक्ति देने वाला है। क्योंकि खेल अत्यंत संसाधन-विवश कार्यक्रम हैं, दक्षता कई मामलों में स्थिरता से पहले जाती है। कुछ कार्यों के लिए अपनी स्वयं की, बहुत विशिष्ट डेटा-संरचनाओं और एल्गोरिदम को लिखना बहुत महत्वपूर्ण हो सकता है, भले ही यह किसी भी प्रकार के सॉफ़्टवेयर विकास के "सर्वोत्तम तरीकों" के खिलाफ हो। इसका एक अच्छा उदाहरण डेटा ओरिएंटेड डिज़ाइन हो सकता है जिसमें आप वास्तविक डेटा के बजाय अपने डेटा को समान डेटा सरणियों में संग्रहीत करते हैं। यह स्थानीयता के संदर्भ को बढ़ाने के लिए है और इस तरह के सीपीयू कैश दक्षता में वृद्धि। व्यावहारिक नहीं, लेकिन दिए गए डोमेन में बहुत महत्वपूर्ण है।


1

यह हमेशा एक कठिन सवाल होता है और मुझे जवाब एक तरह से झूलते दिखाई देते हैं, इसलिए मैं दूसरे पक्ष के लिए खेल खेलूंगा, हालांकि मैं यह दावा नहीं करता कि इसका उत्तर सही है, यह बहुत ही नरम और मामला-दर-मामला है।

एक जटिल लेकिन उच्च प्रदर्शन समाधान के बारे में एक बात यह है कि आप हमेशा बस जीवित बिल्ली को इससे बाहर निकाल सकते हैं। मैं आमतौर पर सेल्फ-डॉक्यूमेंटिंग कोड का प्रशंसक हूं, लेकिन मैं सॉफ्टवेयर का भी प्रशंसक हूं, जो समय की एक ऐसी मात्रा में प्रतिक्रिया करता है जिससे मुझे लगता है कि यह मुझे धीमा नहीं कर रहा है। यदि आप जटिल लेकिन उच्च प्रदर्शन समाधान के साथ जाते हैं, तो विचार करें कि आप इसे इतना बुरा नहीं बनाने के लिए क्या कर सकते हैं:

इसे एक इंटरफ़ेस में लपेटें, इसे खुद पर एक असेंबली में डालें, संभवतः यह भी एक प्रक्रिया है। लीक से बचने के लिए जितना संभव हो उतना मोटी अमूर्त दीवार के साथ इसे जितना संभव हो उतना शिथिल रूप से युग्मित करें । भविष्य में प्रतिगमन को बचाने के लिए इसके लिए बहुत सारे यूनिट परीक्षण लिखें।

इसे कोड में दस्तावेज करें, यहां तक ​​कि कुछ वास्तविक दस्तावेज लिखने पर भी विचार करें। जटिल डेटा संरचनाओं के बारे में सोचें और उन्हें कैसे प्रलेखित किया गया है, इसकी व्याख्या करने के लिए डेटा संरचना पुस्तक / विकिपीडिया लेख के बिना कोड से उनमें से किसी एक के कार्यान्वयन को समझने की कोशिश करें। और फिर भी हम सभी स्वीकार करते हैं कि ये जटिल डेटा संरचना वास्तव में अच्छी चीजें हैं और यह फायदेमंद है कि किसी ने उन्हें हमारी भाषाओं में लागू किया।

याद रखें कि हम सभी एक टीसीपी / आईपी स्टैक पर संदेश भेज रहे हैं जो संभवतः कोड के रूप में है क्योंकि यदि हम में से कोई भी इसे देख सकता है तो कोड प्राप्त कर सकता है, इसलिए यह उस तरह से प्रदर्शन करता है जैसे हम सभी को इसकी आवश्यकता होती है। शायद आपकी समस्या को अनुकूलन के इस स्तर की आवश्यकता नहीं है, शायद यह करता है, लेकिन इस प्रश्न से निपटने के दौरान सावधान रहें क्योंकि हम सभी को समय-समय पर: वहाँ ड्रेगन होना चाहिए।


0

मैं इस क्षेत्र में काम कर रहा हूं जहां कोई प्रदर्शन SLA नहीं है। जब कंप्यूटर ग्राफिक्स में ऑफ़लाइन रेंडरर्स की बात आती है, तो उपयोगकर्ताओं के लिए "संतोषजनक प्रदर्शन" नहीं होता है, क्योंकि वे पहले से ही क्लाउड भर में कंप्यूटिंग वितरित करने और अत्याधुनिक रेंडरर्स के साथ भी फार्मों को प्रस्तुत करने के लिए भारी रकम निकाल रहे हैं। फिल्मों के लिए उत्पादन-गुणवत्ता छवियों और फ़्रेमों का उत्पादन करने के लिए, उदा

लेकिन मुझे इस डोमेन में कई वर्षों से काम कर रहे एक व्यक्ति के रूप में कहना है कि कोई भी समाधान जो दक्षता के पक्ष में स्थिरता को कम करता है, वास्तव में कभी-कभी स्थानांतरण की आवश्यकताओं के खिलाफ काम कर रहा है। क्योंकि यदि आप प्रभावी रूप से आने वाले वर्षों के लिए अपने समाधान को बनाए नहीं रख सकते हैं, क्योंकि चीजें आपके पैरों के नीचे शिफ्ट हो रही हैं (दोनों आसपास के कोड के संदर्भ में और उपयोगकर्ताओं को उम्मीद है कि प्रतियोगी एक दूसरे से बेहतर प्रदर्शन करते रहें), तो आपका समाधान पहले से ही अप्रचलन की दिशा में काम कर रहा है और में थोक प्रतिस्थापन की जरूरत है।

मैं अपने कोड को तेज़ी से चलाने के लिए वीट्यून जैसे प्रोफाइलर्स का अंतिम उद्देश्य नहीं देखता। उनका अंतिम मूल्य यह सुनिश्चित करना है कि मैं अपनी उत्पादकता को कभी-न-कभी प्रदर्शन की माँगों को पूरा करने के लिए नीचा नहीं कर रहा हूँ। अगर मुझे पूरी तरह से कुछ स्थूल दिखने वाले माइक्रो-ऑप्टिमाइज़ेशन को लागू करना है, तो प्रोफाइलर, इसे वास्तविक दुनिया के उपयोगकर्ता मामलों के खिलाफ चलाने के साथ जोड़ देगा (और कुछ परीक्षण के मामले में जिसकी मैं कल्पना कर सकता हूं यह महत्वपूर्ण सकता है) नहीं है, यह सुनिश्चित करता है कि मैं इस तरह के अनिवार्य रूप से सकल-दिखने वाला अनुकूलन बहुत, केवल बहुत ही हॉटस्पॉट्स के लिए बहुत ही विवेकपूर्ण रूप से और साथ ही साथ बहुत ही सावधानी से उन्हें दस्तावेज करते हुए दिखाई देते हैं क्योंकि मुझे अनिवार्य रूप से फिर से आना और बनाए रखना और ट्विक करना होगा और आने वाले वर्षों के लिए उन्हें बदलना होगा यदि वह समाधान व्यवहार्य रहता है।

और विशेष रूप से यदि आपके अनुकूलित समाधान में अधिक युग्मन शामिल है, तो मैं वास्तव में इसका उपयोग करने के लिए अनिच्छुक रहूंगा। सबसे मूल्यवान मीट्रिक के बीच मैं कोडबेस के सबसे अधिक प्रदर्शन वाले महत्वपूर्ण क्षेत्रों में सराहना करने के लिए आया हूं, डिकॉउलिंग है (जैसा कि कुछ काम करने के लिए आवश्यक जानकारी की मात्रा को कम करने में, जो उसी तरह इसकी संभावना को कम करता है जब तक कि आपको सीधे बदलाव की आवश्यकता न हो। ), क्योंकि उन महत्वपूर्ण क्षेत्रों में चीजों को बदलने के कारणों को काफी गुणा किया जाता है। जिसका अर्थ है कि किसी काम के लिए कम जानकारी की आवश्यकता होती है, परिवर्तन के लिए कम कारण, और परिवर्तन के कारणों को कम करना वास्तव में मेरे विशेष ध्यान देने वाले क्षेत्रों में उत्पादकता में सुधार का एक बड़ा हिस्सा है क्योंकि चीजों को वैसे भी लगातार बदलना है (हम 'अन्यथा एक वर्ष में अप्रचलित हो जाएगा),

मेरे लिए सबसे बड़ा और सबसे प्रभावी उपाय जो मैंने पाया है, वे हैं जहां दक्षता और स्थिरता और उत्पादकता एक-दूसरे के विपरीत नहीं हैं। मेरे लिए खोज इन अवधारणाओं को सामंजस्यपूर्ण बनाने की कोशिश करना है क्योंकि एक संभवतः इसे बना सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.