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

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

मैंने इसे सी # में करने की कोशिश की:

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncTest
{
    class Program
    {
        static void RunSeconds(double seconds)
        {
            int ms = (int)(seconds * 1000);

            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            Console.WriteLine($"Thread started to run for {seconds} seconds");
            Thread.Sleep(ms);
            stopwatch.Stop();

            Console.WriteLine($"Stopwatch passed {stopwatch.ElapsedMilliseconds} ms.");
        }

        static async Task RunSecondsAsync(double seconds)
        {
            int ms = (int)(seconds * 1000);

            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            Console.WriteLine($"Thread started to run for {seconds} seconds");
            await Task.Run(() => Thread.Sleep(ms));
            stopwatch.Stop();

            Console.WriteLine($"Stopwatch passed {stopwatch.ElapsedMilliseconds} ms.");
        }

        static void RunSecondsThreaded(double seconds)
        {
            Thread th = new Thread(() => RunSeconds(seconds));
            th.Start();
        }

        static async Task Main()
        {
            Console.WriteLine("Synchronous:");
            RunSeconds(2.5); RunSeconds(2);

            Console.WriteLine("\nAsynchronous:");
            Task t1 = RunSecondsAsync(2.5); Task t2 = RunSecondsAsync(2);
            await t1; await t2;

            Console.WriteLine("\nMultithreading:");
            RunSecondsThreaded(2.5); RunSecondsThreaded(2);
        }
    }
}

परिणाम:

Synchronous:
Thread started to run for 2.5 seconds
Stopwatch passed 2507 ms.
Thread started to run for 2 seconds
Stopwatch passed 2001 ms.

Asynchronous:
Thread started to run for 2.5 seconds
Thread started to run for 2 seconds
Stopwatch passed 2002 ms.
Stopwatch passed 2554 ms.

Multithreading:
Thread started to run for 2.5 seconds
Thread started to run for 2 seconds
Stopwatch passed 2000 ms.
Stopwatch passed 2501 ms.

वे अनिवार्य रूप से वही परिणाम, व्यवहार-वार प्राप्त हुए। तो एक मल्टीथ्रेडेड प्रोग्राम बनाम एसिंक्रोनस एक के व्यवहार में मुझे वास्तव में कब और क्या अलग मिलेगा?

मेरे पास हल करने के लिए कई अन्य मुद्दे हैं:

इस छवि में, उदाहरण के लिए:

enter image description here

मुझे जो नहीं मिलता है वह यह है कि जब आप एक एसिंक्रोनस प्रोग्राम चलाते हैं, तो यह व्यावहारिक रूप से एक बहुप्रचारित के समान व्यवहार करता है, जिसमें ऐसा लगता है कि यह समान समय व्यतीत करता है। ऊपर की छवि के अनुसार, यह "ब्रेक" में अतुल्यकालिक कार्य को संबोधित कर रहा है। यदि यह ऐसा करता है, तो क्या एसिंक्रोनस कार्य को पूरा करने में अधिक समय नहीं लगना चाहिए?

मान लें कि एक अतुल्यकालिक कार्य जो सामान्य रूप से अन्य कार्यों को लॉक करते समय 3 सेकंड को समकालिक रूप से पूरा करेगा, क्या मुझे इन कार्यों को 3 सेकंड से अधिक समय में समाप्त करने की उम्मीद नहीं करनी चाहिए, यह देखते हुए कि यह मेरे मूल कार्य से ब्रेक लेते समय पक्ष में अन्य कार्य करता है ?

तो यह अक्सर एक समान अतुल्यकालिक (यानी सामान्य 3 सेकंड) क्यों लेता है? और प्रोग्राम "रेस्पॉन्सिव" क्यों बन जाता है: यदि कार्य एक अलग थ्रेड पर नहीं किया जा रहा है, तो साइड पर अन्य कार्यों पर काम करते हुए कार्य पर काम करने में केवल अपेक्षित 3 सेकंड क्यों लगते हैं?

मेरी समस्या एक रेस्तरां में श्रमिकों का उपयोग करने वाले उदाहरणों के साथ है। a> (शीर्ष उत्तर देखें), यह है कि एक रेस्तरां में, ओवन द्वारा खाना पकाने का काम किया जाता है। एक कंप्यूटर में, यह सादृश्य ज्यादा मायने नहीं रखता है, क्योंकि यह स्पष्ट नहीं है कि ओवन को एक अलग "धागा" के रूप में क्यों नहीं माना जा रहा है, लेकिन लोग/श्रमिक हैं।

इसके अलावा, क्या एक बहुप्रचारित एप्लिकेशन अधिक मेमोरी का उपयोग करता है? और अगर ऐसा होता है, तो क्या यह साबित करने के लिए एक साधारण एप्लिकेशन (आदर्श रूप से ऊपर के समान) बनाना संभव है?

एक लंबा सवाल है, लेकिन मल्टीथ्रेडिंग और एसिंक्रोनस प्रोग्रामिंग के बीच अंतर मेरे लिए स्पष्ट नहीं है।

3
Osama Kawish 4 जुलाई 2020, 15:03

2 जवाब

सबसे बढ़िया उत्तर

आप async कोड में Thread.Sleep का उपयोग नहीं कर सकते, उपयोग करें

await Task.Delay(1000); 

बजाय।

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

जब आप सीधे थ्रेड के साथ हेरफेर करते हैं, तो आप ब्लॉक कर देते हैं और आपका कोड एसिंक्स नहीं रह जाता है, आप थ्रेडपूल को भी भूखा रखते हैं क्योंकि यह उपलब्ध थ्रेड्स की संख्या में सीमित है।

साथ ही एक एसिंक विधि के पूरे जीवनकाल में, आपको गारंटी नहीं है कि प्रत्येक पंक्ति एक ही धागे पर निष्पादित की जाएगी। आम तौर पर प्रत्येक प्रतीक्षित कीवर्ड के बाद धागा बदल सकता है।

आप कभी भी एसिंक विधि में थ्रेड क्लास को स्पर्श नहीं करना चाहते हैं।

ऐसा करके:

await Task.Run(() => Thread.Sleep(ms));

आप टीपीएल को पूल से बाहर एक धागा आवंटित करने के लिए मजबूर करते हैं, इसे भूखा रखने के लिए। ऐसा करके

await Task.Run(async () => await Task.Delay(ms));

आप अनिवार्य रूप से पूल से एक या दो धागे पर चलेंगे, भले ही आप इसे कई बार शुरू करें।

सिंक्रोनस कोड पर टास्क। रन () चलाना ज्यादातर लीगेसी कॉल के लिए उपयोग किया जाता है जो आंतरिक रूप से एसिंक्स का समर्थन नहीं करता है और टीपीएल सिंक कॉल को पूल किए गए थ्रेड में लपेटता है। async कोड का पूरा लाभ प्राप्त करने के लिए आपको एक कॉल की प्रतीक्षा करनी होगी जो स्वयं केवल async कोड को आंतरिक रूप से चलाती है।

4
NIKER 4 जुलाई 2020, 15:20

मैं आपके कार्यक्रम को वास्तविक दुनिया के उदाहरण के साथ सहसंबंधित करने का प्रयास करता हूं और फिर इसे समझाता हूं।

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

कार्यक्रमों का निष्पादन प्रारंभ:

static async Task Main()
{
    Process process = Process.GetCurrentProcess();
    Console.WriteLine("Synchronous:");

आप मुख्य द्वार से कार्यालय में प्रवेश करते हैं और अपनी डायरी में "सिंक्रोनस:" दर्ज करते हैं।

Synchronous:

कॉलिंग विधि 'रनसेकंड ()'

RunSeconds(2.5); RunSeconds(2);

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

Thread started to run for 2.5 seconds
Stopwatch passed 2507 ms.
Thread started to run for 2 seconds
Stopwatch passed 2001 ms.

Console.WriteLine("\nAsynchronous:");

फिर आप डायरी में "एसिंक्रोनस:" लॉग इन करें

कॉलिंग विधि 'RunSecondsAsync ()'

Task t1 = RunSecondsAsync(2.5); Task t2 = RunSecondsAsync(2);
await t1; await t2;

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

Thread started to run for 2.5 seconds
Thread started to run for 2 seconds
Stopwatch passed 2002 ms.
Stopwatch passed 2554 ms.

Console.WriteLine("\Multithreading:");

फिर आप डायरी में "मल्टीथ्रेडिंग:" लॉग इन करें

कॉलिंग विधि 'RunSecondsThreaded ()'

RunSecondsThreaded(2.5); RunSecondsThreaded(2);

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

Thread started to run for 2.5 seconds
Thread started to run for 2 seconds
Stopwatch passed 2000 ms.
Stopwatch passed 2501 ms.

आशा है कि यह आपके भ्रम को दूर करने में मदद करेगा

1
Durga Prasad 4 जुलाई 2020, 17:41