अतुल्यकालिक प्रोग्रामिंग और मल्टीथ्रेडिंग के बीच अंतर क्या है?


234

मैंने सोचा था कि वे मूल रूप से एक ही चीज थे - प्रोग्राम लिखना जो प्रोसेसर के बीच कार्यों को विभाजित करते हैं (मशीनों पर 2+ प्रोसेसर हैं)। तब मैं पढ़ रहा हूँ इस है, जो कहते हैं:

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

Async और प्रतीक्षा कीवर्ड के कारण अतिरिक्त थ्रेड्स का निर्माण नहीं होता है। Async विधियों के लिए मल्टीथ्रेडिंग की आवश्यकता नहीं है क्योंकि एक async विधि अपने स्वयं के थ्रेड पर नहीं चलती है। विधि वर्तमान सिंक्रनाइज़ेशन संदर्भ पर चलती है और थ्रेड पर समय का उपयोग केवल तब होता है जब विधि सक्रिय होती है। CPU- बाउंड वर्क को बैकग्राउंड थ्रेड में ले जाने के लिए आप Task.Run का उपयोग कर सकते हैं, लेकिन एक बैकग्राउंड थ्रेड ऐसी प्रक्रिया से मदद नहीं करता है, जो परिणाम उपलब्ध होने का इंतजार कर रही है।

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

अब मैं अतुल्यकालिक कार्यों के विचार को समझता हूं जैसे पीजी पर उदाहरण। जॉन स्कीट के सी # में 467 गहराई, तीसरा संस्करण

async void DisplayWebsiteLength ( object sender, EventArgs e )
{
    label.Text = "Fetching ...";
    using ( HttpClient client = new HttpClient() )
    {
        Task<string> task = client.GetStringAsync("http://csharpindepth.com");
        string text = await task;
        label.Text = text.Length.ToString();
    }
}

asyncकीवर्ड का अर्थ है " यह समारोह, जब भी यह कहा जाता है, एक संदर्भ में इसके पूरा होने के लिए सब कुछ के लिए आवश्यक है इसके कॉल के नाम से जाना के बाद में कहा जाता है नहीं किया जाएगा।"

दूसरे शब्दों में, इसे किसी कार्य के बीच में लिखना

int x = 5; 
DisplayWebsiteLength();
double y = Math.Pow((double)x,2000.0);

, के बाद से DisplayWebsiteLength()कोई लेना देना नहीं है xया y, कारण होगा DisplayWebsiteLength()"पृष्ठभूमि में" निष्पादित किया जाना है, की तरह

                processor 1                |      processor 2
-------------------------------------------------------------------
int x = 5;                                 |  DisplayWebsiteLength()
double y = Math.Pow((double)x,2000.0);     |

जाहिर है कि यह एक मूर्खतापूर्ण उदाहरण है, लेकिन क्या मैं सही हूं या मैं पूरी तरह से भ्रमित हूं या क्या?

(इसके अलावा, मैं क्यों के बारे में उलझन में हूँ senderऔर eकभी ऊपर समारोह के मुख्य भाग में उपयोग नहीं किया जाता।)


13
यह एक अच्छी व्याख्या है: blog.stephencleary.com/2013/11/there-is-no-thread.html
Jakub Lortz

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


3
DisplayWebsiteLengthकोड नमूने पर एक बहुत ही महत्वपूर्ण नोट : आपको HttpClientएक usingबयान में उपयोग नहीं करना चाहिए - एक भारी लोड के तहत, कोड सॉकेट की संख्या को समाप्त कर सकता है जिसके परिणामस्वरूप सॉकेटएक्सपेप्शन त्रुटियां हैं। अनुचित इंस्टेंटेशन पर अधिक जानकारी ।
गण

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

जवाबों:


589

आपकी गलतफहमी बेहद आम है। कई लोगों को सिखाया जाता है कि मल्टीथ्रेडिंग और एसिंक्रोनसी एक ही चीज है, लेकिन वे नहीं हैं।

एक सादृश्य आमतौर पर मदद करता है। आप एक रेस्तरां में खाना बना रहे हैं। अंडे और टोस्ट के लिए एक ऑर्डर आता है।

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

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

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

तो आइए जॉन के उदाहरण को अधिक विस्तार से देखें। क्या होता है?

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

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


8
@ user5648283: कार्यों के बारे में सोचने के लिए हार्डवेयर गलत स्तर है। एक कार्य केवल एक वस्तु है जो (1) दर्शाता है कि भविष्य में एक मूल्य उपलब्ध हो जाएगा और (2) उस मूल्य के उपलब्ध होने पर (सही धागे पर) कोड चला सकता है । कोई भी व्यक्तिगत कार्य भविष्य में परिणाम कैसे प्राप्त करता है यह उस पर निर्भर है। कुछ विशेष हार्डवेयर जैसे "डिस्क" और "नेटवर्क कार्ड" का उपयोग करेंगे; कुछ CPU जैसे हार्डवेयर का उपयोग करेंगे।
एरिक लिपर्ट

13
@ user5648283: फिर से, मेरे सादृश्य के बारे में सोचें। जब कोई आपसे अंडे और टोस्ट पकाने के लिए कहता है, तो आप विशेष हार्डवेयर का उपयोग करते हैं - एक स्टोव और एक टोस्टर - और आप रसोई को साफ कर सकते हैं जबकि हार्डवेयर अपना काम कर रहा है। अगर कोई आपसे अंडे, टोस्ट, और आखिरी हॉबिट मूवी का एक मूल समालोचक पूछता है, तो आप अपनी समीक्षा लिख ​​सकते हैं जबकि अंडे और टोस्ट खाना बना रहे हैं, लेकिन आपको इसके लिए हार्डवेयर का उपयोग करने की आवश्यकता नहीं है।
एरिक लिपर्ट

9
@ user5648283: अब "कोड को फिर से व्यवस्थित करने" के बारे में आपके प्रश्न के लिए, इस पर विचार करें। मान लीजिए कि आपके पास एक विधि P है जिसमें पैदावार वापसी है, और एक विधि Q है जो कोड के माध्यम से P. Step के परिणाम पर फ़ॉरच करता है। आप देखेंगे कि हम थोड़ा क्यू चलाते हैं, फिर थोड़ा पी के फिर थोड़ा क्यू के ... क्या आप उस की बात समझते हैं? प्रतीक्षा अनिवार्य रूप से फैंसी ड्रेस में वापसी है । अब यह अधिक स्पष्ट है?
एरिक लिपर्ट

10
टोस्टर हार्डवेयर है। हार्डवेयर को इसे सेवा करने के लिए किसी धागे की आवश्यकता नहीं है; डिस्क और नेटवर्क कार्ड और व्हाट्सएप ओएस थ्रेड्स के नीचे एक स्तर पर चलते हैं।
एरिक लिपर्ट

5
@ शिवप्रसादकौरला: यह बिल्कुल सच नहीं है । यदि आप ऐसा मानते हैं, तो आपके पास अतुल्यकालिक के बारे में कुछ बहुत गलत धारणाएं हैं । C # में एसिंक्रोनस का पूरा बिंदु यह है कि यह एक थ्रेड नहीं बनाता है।
एरिक लिपर्ट

27

इन-ब्राउज़र जावास्क्रिप्ट एक अतुल्यकालिक कार्यक्रम का एक बड़ा उदाहरण है जिसमें कोई थ्रेड नहीं है।

आपको एक ही समय में एक ही ऑब्जेक्ट को छूने वाले कोड के कई टुकड़ों के बारे में चिंता करने की ज़रूरत नहीं है: प्रत्येक फ़ंक्शन पेज पर चलने के लिए किसी भी अन्य जावास्क्रिप्ट को चलाने से पहले समाप्त हो जाएगा।

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

C # एप्लिकेशन में, जब भी आप UI तत्वों के साथ काम कर रहे होते हैं, तब वही होता है - जब आप UI थ्रेड पर होते हैं, तो आपको केवल UI तत्वों के साथ सहभागिता करने की अनुमति होती है। यदि उपयोगकर्ता ने एक बटन क्लिक किया है, और आप डिस्क से एक बड़ी फ़ाइल को पढ़कर प्रतिक्रिया देना चाहते हैं, तो एक अनुभवहीन प्रोग्रामर स्वयं क्लिक इवेंट हैंडलर के भीतर फ़ाइल को पढ़ने की गलती कर सकता है, जिससे एप्लिकेशन "फ्रीज" तक हो जाएगा। फ़ाइल लोड करना समाप्त हो गया क्योंकि इसे किसी भी अधिक क्लिकिंग, होवरिंग, या किसी अन्य UI से संबंधित घटनाओं का जवाब देने की अनुमति नहीं है, जब तक कि उस धागे को मुक्त नहीं किया जाता है।

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

यदि आप सोचते हैं कि सीपीयू हार्डवेयर और ऑपरेटिंग सिस्टम के स्तर पर एक फ़ाइल को पढ़ते समय क्या कर रहा है, तो यह मूल रूप से डिस्क से डेटा के टुकड़ों को मेमोरी में पढ़ने, और ऑपरेटिंग सिस्टम को "बाधा" के साथ हिट करने के लिए एक निर्देश जारी कर रहा है। “जब पूरा हो गया। दूसरे शब्दों में, डिस्क से पढ़ना (या वास्तव में I / O) एक स्वाभाविक रूप से अतुल्यकालिक ऑपरेशन है। एक सूत्र की प्रतीक्षा है कि I / O के पूरा होने की प्रतीक्षा में लाइब्रेरी डेवलपर्स ने इसके खिलाफ प्रोग्राम करना आसान बना दिया है। यह आवश्यक नहीं है।

अब, .NET में अधिकांश I / O परिचालनों में एक समान ...Async()विधि है जिसे आप आमंत्रित कर सकते हैं, जो Taskलगभग तुरंत लौटता है । आप Taskउस कोड को निर्दिष्ट करने के लिए कॉलबैक जोड़ सकते हैं जिसे आप अतुल्यकालिक ऑपरेशन पूरा होने पर चलाना चाहते हैं। आप यह भी निर्दिष्ट कर सकते हैं कि आप उस थ्रेड को किस कोड पर चलाना चाहते हैं, और आप एक टोकन प्रदान कर सकते हैं, जो एसिंक्रोनस ऑपरेशन समय-समय पर देख सकते हैं कि क्या आपने एसिंक्रोनस कार्य को रद्द करने का निर्णय लिया है, जिससे इसे अपना काम जल्दी से बंद करने का अवसर मिलता है। और शान से।

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

तो आप अपने UI ईवेंट हैंडलर awaitको I / O ऑपरेशन कर सकते हैं, यूआई थ्रेड को अन्य चीजों को करने के लिए मुक्त कर सकते हैं, और अधिक-या-कम स्वचालित रूप से यूआई थ्रेड में लौटते हुए एक बार जब आप फ़ाइल को पढ़ते हैं - बिना कभी एक नया सूत्र बनाएँ।


केवल एक जावास्क्रिप्ट "थ्रेड" चल रहा है - अब वेब वर्कर्स के साथ सच नहीं है ।
ओलेक्सी

6
@oleksii: यह तकनीकी रूप से सच है, लेकिन मैं इसमें नहीं जा रहा था क्योंकि वेब वर्कर्स एपीआई स्वयं अतुल्यकालिक है, और वेब वर्कर्स को जावास्क्रिप्ट वैल्यूज या DOM को उस वेब पेज पर प्रभावित करने की अनुमति नहीं है जिसका वे आह्वान कर रहे हैं। से, जिसका अर्थ है कि इस उत्तर का महत्वपूर्ण दूसरा पैराग्राफ अभी भी सही है। प्रोग्रामर के दृष्टिकोण से, वेब कार्यकर्ता को आमंत्रित करने और AJAX अनुरोध को लागू करने के बीच बहुत कम अंतर है।
स्ट्रिपलिंगवर्यर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.