सिंक्रोनस और एसिंक्रोनस प्रोग्रामिंग के बीच अंतर क्या है (नोड में)


189

मैं नोडबेगिनर पढ़ रहा हूं और मैं निम्नलिखित दो टुकड़ों में आया हूं।

पहले वाला:

    var result = database.query("SELECT * FROM hugetable");
    console.log("Hello World");

दूसरा एक:

    database.query("SELECT * FROM hugetable", function(rows) {
       var result = rows;
    });
    console.log("Hello World");

मुझे लगता है कि वे क्या करने वाले हैं, वे क्वेरी का उत्तर प्राप्त करने के लिए डेटाबेस को क्वेरी करते हैं। और फिर console.log('Hello world')

पहले वाला माना जाता है कि समकालिक कोड है। और दूसरा एक अतुल्यकालिक कोड है।

दो टुकड़ों के बीच का अंतर मेरे लिए बहुत अस्पष्ट है। आउटपुट क्या होगा?

अतुल्यकालिक प्रोग्रामिंग पर Googling ने मेरी मदद नहीं की।


41
Stange आपको Google के साथ कुछ भी नहीं मिला, यह एक बड़ा विषय है। सिंक्रोनस प्रोग्रामिंग में, प्रत्येक चरण को पिछले एक के बाद एक निष्पादित किया जाता है। एसिंक्रोनस में, चरण 2 समाप्त नहीं होने पर भी प्रदर्शन किया जाएगा। आपके दूसरे उदाहरण में परिभाषित फ़ंक्शन को कॉलबैक फ़ंक्शन कहा जाता है, और डेटाबेस से परिणाम जैसे ही लौटाया जाएगा, जो संभवतः कंसोल.लॉग के चलने के बाद होगा।
लॉरेंट एस

7
@Bartdude अतुल्यकालिक प्रोग्रामिंग पर बहुत कुछ था, लेकिन यह क्या है, और व्यवहार में इसका क्या अर्थ है, इस पर कोई सरल व्याख्या नहीं है।
अज़ीरा

1
@GabrielLlamas हमें तुल्यकालिक कार्यों से क्यों बचना चाहिए?
चार्ली पार्कर

3
@CharlieParker क्योंकि वे इवेंट लूप को ब्लॉक करते हैं और आप एक अतुल्यकालिक ईवेंट I / O मॉडल से सभी लाभ खो रहे हैं। और क्योंकि यह एक बुरा अभ्यास है। इसके बारे में इस तरह से सोचें: यदि आप अतुल्यकालिक कार्यों का उपयोग नहीं कर रहे हैं, तो आप Node.js का उपयोग क्यों कर रहे हैं?
गेब्रियल लामास

1
@GabrielLlamas, अगर मैं एक INSERT क्वेरी को निष्पादित कर रहा हूं और मैं अंतिम सम्मिलित आईडी का उपयोग करना चाहता हूं database.query(), तो मुझे इसे समकालिक रूप से कॉल करना चाहिए, है ना? या दृष्टिकोण क्या होना चाहिए? (यह सवाल मेरे पास लंबे समय से है)
सैन

जवाबों:


225

अंतर यह है कि पहले उदाहरण में , कार्यक्रम पहली पंक्ति में ब्लॉक करेगा। अगली लाइन ( console.log) का इंतजार करना होगा।

में दूसरे उदाहरण , console.logजबकि क्वेरी कार्रवाई की जा रही है निष्पादित किया जाएगा। यही है, क्वेरी को पृष्ठभूमि में संसाधित किया जाएगा, जबकि आपका कार्यक्रम अन्य चीजें कर रहा है, और एक बार क्वेरी डेटा तैयार हो जाने के बाद, आप इसके साथ जो चाहें करेंगे।

तो, संक्षेप में: पहला उदाहरण ब्लॉक करेगा, जबकि दूसरा नहीं होगा।

निम्नलिखित दो उदाहरणों का आउटपुट:

// Example 1 - Synchronous (blocks)
var result = database.query("SELECT * FROM hugetable");
console.log("Query finished");
console.log("Next line");


// Example 2 - Asynchronous (doesn't block) 
database.query("SELECT * FROM hugetable", function(result) {
    console.log("Query finished");
});
console.log("Next line");

होने वाला:

  1. Query finished
    Next line
  2. Next line
    Query finished

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

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

यहां आप इस बारे में और अधिक पढ़ सकते हैं: Node.js में सिंगल थ्रेडेड नॉन ब्लॉकिंग IO मॉडल कैसे काम करता है


9
इसलिए मूल रूप से, जब मैं कोड के पहले टुकड़े को निष्पादित करता हूं, तो यह कुछ ऐसा करेगा request query.; 5 seconds later when the request is done; console.log:; जब कोई दूसरा निष्पादित करता है request query; console.log; work on the query:;
अज़ीरा

1
@ जॉन्गल्ट एसक्यूएल एक अलग धागे पर चलता है। लेकिन निश्चित रूप से जो आपके द्वारा उपयोग किए जाने वाले sql ड्राइवर के कार्यान्वयन पर निर्भर करता है। ड्राइवर को एक नया धागा स्पॉन करना चाहिए, mysql से कनेक्ट करना चाहिए और क्वेरी चलाना चाहिए। एक बार हो जाने के बाद, परिणाम को घटना कतार में पोस्ट करें , और नोड कॉलबैक कॉल करेगा।
साल्वेटरबेल

4
क्या यह async उदाहरण के लिए # 1 जैसी ही चीज़ का उत्पादन करना संभव नहीं है? उदाहरण के लिए, database.queryइतनी तेजी से खत्म होता है कि जब तक हम console.logकाम पर पहुंचते हैं , तब तक काम पूरा हो चुका होता है।
महानवमी

2
@ TheBronx अगर console.log("Next line");उदाहरण 2 में अनाम फ़ंक्शन के अंदर था, तो उसके ठीक बाद console.log("query finished");, इसका मतलब होगा कि "अगली पंक्ति" को "क्वेरी समाप्त" अधिकार के बाद मुद्रित किया जाएगा? इसलिए, अगर मेरे पास एक नेस्टेड फैशन में सब कुछ है, तो सब कुछ एक तुल्यकालिक फैशन में चलेगा, इस प्रकार मुझे कुछ कार्यों के तुल्यकालिक संस्करणों का उपयोग करने के बारे में चिंता करने की आवश्यकता नहीं होगी। क्या मैं अपनी समझ में सही हूं?
अब्दुल

4
संक्षिप्त उत्तर : हां @ अब्दुल, आप सही कह रहे हैं। लंबे उत्तर : नेस्टिंग फ़ंक्शन (कॉलबैक) चीजों को क्रमिक रूप से करने का तरीका है, "एक के बाद एक"। लेकिन वह तकनीकी रूप से "सिंक्रोनस" नहीं है। अनाम फ़ंक्शन को अभी भी निष्पादित किया जाता है "जब अवरुद्ध ऑपरेशन समाप्त हो गया है", या दूसरे शब्दों में, "अतुल्यकालिक"। Node.js अन्य कार्यों को अंजाम दे सकता है जबकि ब्लॉकिंग ऑपरेशन हो रहा है। फ़ंक्शंस async रहते हैं, इसका बस यही है कि आप उनका पीछा कर रहे हैं। समन्वयन फ़ंक्शन ब्लॉक निष्पादन, यह कुंजी है।
साल्वेटेरलैब

74

इन दो दृष्टिकोणों के बीच अंतर इस प्रकार है:

समकालिक तरीका: यह प्रत्येक ऑपरेशन के पूरा होने की प्रतीक्षा करता है, उसके बाद ही यह अगले ऑपरेशन को अंजाम देता है। आपकी क्वेरी के लिए: console.log()कमांड को तब तक निष्पादित नहीं किया जाएगा, जब तक कि डेटाबेस से सभी परिणाम प्राप्त करने के लिए क्वेरी को निष्पादित करना समाप्त न हो जाए।

अतुल्यकालिक तरीका: यह कभी भी प्रत्येक ऑपरेशन के पूरा होने की प्रतीक्षा नहीं करता है, बल्कि यह केवल पहले GO में सभी ऑपरेशनों को निष्पादित करता है। रिजल्ट उपलब्ध होते ही प्रत्येक ऑपरेशन का काम संभाला जाएगा। आपकी क्वेरी के लिए: विधि के console.log()तुरंत बाद कमांड निष्पादित किया जाएगा Database.Query()। जबकि डेटाबेस क्वेरी बैकग्राउंड में चलती है और डेटा पुनः प्राप्त करने के बाद परिणाम को लोड करती है।

बक्सों का इस्तेमाल करें

  1. यदि आपके ऑपरेशन डीबी से भारी डेटा को क्वेरी करने जैसे बहुत भारी उठाने नहीं कर रहे हैं, तो सिंक्रोनस तरीके से आगे बढ़ें अन्यथा एसिंक्रोनस तरीके से।

  2. अतुल्यकालिक तरीके से आप उपयोगकर्ता को कुछ प्रगति सूचक दिखा सकते हैं जबकि पृष्ठभूमि में आप अपने भारी वजन के कामों को जारी रख सकते हैं। यह GUI ऐप्स के लिए एक आदर्श परिदृश्य है।


2
इसका मतलब यह है कि db.query (cmd, callback) समवर्ती (धागे में) के रूप में चल रहा है? क्या वे एक ही समय पर चल रहे हैं?
चार्ली पार्कर

अपने दूसरे उदाहरण में, क्या कोई मौका है कि क्वेरी इतनी तेजी से खत्म हो जाए कि वह पहले कॉलबैक को कॉल करे, पहले console.log?
फहमी

@ फाहमी सैद्धांतिक रूप से हां, व्यावहारिक रूप से काफी असंभव है
लियो मेस्सी

24

यदि आप दोनों उदाहरणों के लिए एक पंक्ति जोड़ते हैं तो यह थोड़ा और स्पष्ट हो जाएगा:

var result = database.query("SELECT * FROM hugetable");
console.log(result.length);
console.log("Hello World");

दूसरा एक:

database.query("SELECT * FROM hugetable", function(rows) {
   var result = rows;
   console.log(result.length);
});
console.log("Hello World");

इन्हें चलाने का प्रयास करें, और आप देखेंगे कि पहला (सिंक्रोनस) उदाहरण, result.length 'हैलो वर्ल्ड' लाइन के बाहर मुद्रित किया जाएगा। दूसरे (अतुल्यकालिक) उदाहरण में, परिणाम.लिफ्टिंग (सबसे अधिक संभावना) "हैलो वर्ल्ड" लाइन के बाद मुद्रित किया जाएगा।

ऐसा इसलिए है क्योंकि दूसरे उदाहरण database.queryमें, पृष्ठभूमि में अतुल्यकालिक रूप से चलाया जाता है, और स्क्रिप्ट सीधे "हैलो वर्ल्ड" के साथ जारी रहती है। console.log(result.length)जब डेटाबेस क्वेरी पूरा कर लिया है केवल निष्पादित किया जाता है।


1
आप कहते हैं: result.length (सबसे अधिक संभावना) "हैलो वर्ल्ड" लाइन के बाद मुद्रित किया जाएगा। .... यह केवल "सबसे अधिक संभावना" क्यों होगी? मुझे लगता है कि यह हमेशा कंसोल.लॉग आउटपुट के बाद प्रिंट होता है। :) स्पष्टीकरण के लिए धन्यवाद
humanityANDpeace

9
@humanityANDpeace: यह एसिंक्रोनस एक्सेस का पूरा बिंदु है: आपको नहीं पता कि यह कब किया जाएगा। शायद यह एक बेतुका तेज़ डेटाबेस है, और जावास्क्रिप्ट क्वेरी "हैलो वर्ल्ड" लाइन पर जाने से पहले ही डेटाबेस क्वेरी वापस आ जाती है ...
Martijn

19

सबसे पहले, मुझे एहसास है कि मुझे इस सवाल का जवाब देने में देर हो गई है।

सिंक्रोनस और एसिंक्रोनस पर चर्चा करने से पहले, आइए हम संक्षेप में देखें कि प्रोग्राम कैसे चलते हैं।

में तुल्यकालिक मामले, प्रत्येक कथन कम्प्लिट्स से पहले अगले बयान चलाया जाता है। इस मामले में कार्यक्रम का मूल्यांकन कथनों के क्रम में किया जाता है।

यह अतुल्यकालिक है जावास्क्रिप्ट में काम करता है। जावास्क्रिप्ट इंजन में दो भाग होते हैं, एक भाग जो कोड को देखता है और संचालन को और दूसरा जो कतार को संसाधित करता है। कतार प्रसंस्करण एक धागे में होता है, यही कारण है कि एक समय में केवल एक ही ऑपरेशन हो सकता है।

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

    console.log("Hello World"); 

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

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

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

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

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


6

सिंक्रोनस केस में, SQL क्वेरी को पूरा करने तक कंसोल.लॉग कमांड निष्पादित नहीं किया जाता है।

एसिंक्रोनस केस में, कंसोल.लॉग कमांड को सीधे निष्पादित किया जाएगा। क्वेरी का परिणाम कुछ समय बाद "कॉलबैक" फ़ंक्शन द्वारा संग्रहीत किया जाएगा।


1
लेकिन क्या वास्तव में एक साथ बुलाया जा रहा है? जो चीज मुझे भ्रमित करती है, वह अतुल्यकालिक कोड में है, क्या वास्तविक कोड समानांतर में एक ही समय में चलाया जा रहा है?
चार्ली पार्कर

यह प्रोसेसर पर निर्भर करता है (क्या यह मल्टी-कोर है?) और ऑपरेटिंग सिस्टम। देखें en.wikipedia.org/wiki/Multithreading_(software)#Multithreading
संबंधित

4

मुख्य अंतर अतुल्यकालिक प्रोग्रामिंग के साथ है, आप अन्यथा निष्पादन को रोकते नहीं हैं। जब आप 'अनुरोध' कर रहे हों, तो आप अन्य कोड निष्पादित करना जारी रख सकते हैं।


2

फ़ंक्शन दूसरे को एसिंक्रोनस बनाता है।

अगले एक को जारी रखने से पहले चलाने के लिए प्रत्येक पंक्ति को प्रतीक्षा करने के लिए प्रोग्राम को मजबूर करता है। दूसरा व्यक्ति प्रत्येक पंक्ति को एक साथ (और स्वतंत्र रूप से) एक साथ चलाने की अनुमति देता है।

भाषाएँ और चौखटे (जेएस, नोड.जेएस) जो अतुल्यकालिक या संगामिति की अनुमति देते हैं, उन चीजों के लिए बहुत अच्छा है जिन्हें वास्तविक समय संचरण की आवश्यकता होती है (जैसे चैट, स्टॉक एप्लिकेशन)।


0

सिंकिंग प्रोग्रामिंग

C, C #, Java जैसी प्रोग्रामिंग लैंग्वेजेज सिंकिंग प्रोग्रामिंग हैं, जो भी आप लिखते हैं, वह आपके लेखन के क्रम में निष्पादित होगी।

-GET DATA FROM SQL.
//Suppose fetching data take 500 msec

-PERFORM SOME OTHER FUNCTION.
//Performing some function other will take 100 msec, but execution of other 
//task start only when fetching of sql data done (i.e some other function 
//can execute only after first in process job finishes).

-TOTAL TIME OF EXECUTION IS ALWAYS GREATER THAN (500 + 100 + processing time) 
msec

async

NodeJs, Async फीचर के साथ आता है, यह प्रकृति में गैर-अवरोधक है, किसी भी I / O कार्य में लगता है जो समय ले रहा है (प्राप्त करना, लिखना, पढ़ना), नोड्ज निष्क्रिय नहीं रहेंगे और कार्य समाप्त होने की प्रतीक्षा करेंगे, यह ' मैं कतार में अगले कामों को अंजाम देना शुरू करूँगा, और जब भी वह समय पूरा होगा तो कॉलबैक का उपयोग करके सूचित करेगा। निम्नलिखित उदाहरण से मदद मिलेगी:

//Nodejs uses callback pattern to describe functions.
//Please read callback pattern to understand this example

//Suppose following function (I/O involved) took 500 msec
function timeConsumingFunction(params, callback){
  //GET DATA FROM SQL
  getDataFromSql(params, function(error, results){
    if(error){
      callback(error);
    }
    else{
      callback(null, results);
    }
  })
}

//Suppose following function is non-blocking and took 100 msec
function someOtherTask(){
  //some other task
  console.log('Some Task 1');
  console.log('Some Task 2');
}

console.log('Execution Start');

//Start With this function
timeConsumingFunction(params, function(error, results){
    if(error){
      console.log('Error')
    }
    else{
      console.log('Successfull'); 
    }
  })

//As (suppose) timeConsumingFunction took 500 msec, 
//As NodeJs is non-blocking, rather than remain idle for 500 msec, it will start 
//execute following function immediately
someOtherTask();

शॉर्ट में, आउटपुट इस प्रकार है:

Execution Start
//Roughly after 105 msec (5 msec it'll take in processing)
Some Task 1
Some Task 2
//Roughly After 510 msec
Error/Successful //depends on success and failure of DB function execution

अंतर स्पष्ट है जहाँ सिंक निश्चित रूप से 600 (500 + 100 + प्रसंस्करण समय) से अधिक का समय लेगा, async समय बचाता है।


0

सिंक्रोनस फ़ंक्शंस ब्लॉक हो रहे हैं जबकि एसिंक्रोनस फ़ंक्शंस नहीं हैं। सिंक्रोनस फ़ंक्शंस में, स्टेटमेंट अगले स्टेटमेंट से पहले पूरा हो जाता है। इस स्थिति में, कार्यक्रम का मूल्यांकन ठीक-ठीक बयानों के क्रम में किया जाता है और यदि किसी एक वक्तव्य में बहुत लंबा समय लगता है, तो कार्यक्रम का निष्पादन रोक दिया जाता है।

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

ऑर्थिनल जीथब पर पोस्ट किया गया: लिंक


0

जेएस में अतुल्यकालिक प्रोग्रामिंग:

एक समय का

  • ऐसा होने तक आगे कोड का निष्पादन रोक देता है।
  • क्योंकि यह आगे निष्पादन के इस ठहराव को समकालिक कोड को 'ब्लॉकिंग' कहते हैं। इस अर्थ में ब्लॉक करना कि कोई अन्य कोड निष्पादित नहीं किया जाएगा।

अतुल्यकालिक

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

उदाहरण:

// This function is synchronous
function log(arg) {
    console.log(arg)
}

log(1);

// This function is asynchronous
setTimeout(() => {
    console.log(2)
}, 0);

log(3)

  • उदाहरण 1, 3, 2 को लॉग करता है।
  • 2 अंतिम लॉग इन किया गया है क्योंकि यह एक एसिंक्रोनस फ़ंक्शन के अंदर है जो स्टैक खाली होने के बाद निष्पादित किया जाता है।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.