समानांतर में एसिंक्रोनस कार्य चलाएं

Complete

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

सी # में, आप समानांतर कोड लिखने की प्रक्रिया को सरल बनाने के लिए टास्क समानांतर लाइब्रेरी (टीपीएल) का उपयोग कर सकते हैं। टीपीएल और नामस्थानों में System.ThreadingSystem.Threading.Tasks सार्वजनिक प्रकार और एपीआई का एक सेट है। टीपीएल का उद्देश्य अनुप्रयोगों में समांतरता और संगामिति जोड़ने की प्रक्रिया को सरल बनाकर डेवलपर्स को अधिक उत्पादक बनाना है। टीपीएल गतिशील रूप से सभी उपलब्ध प्रोसेसर का सबसे कुशलता से उपयोग करने के लिए संगामिति की डिग्री को मापता है। इसके अलावा, टीपीएल काम के विभाजन, थ्रेडपूल पर थ्रेड्स के शेड्यूलिंग, रद्दीकरण समर्थन, राज्य प्रबंधन और अन्य निम्न-स्तरीय विवरणों को संभालता है। टीपीएल का उपयोग करके, आप उस कार्य पर ध्यान केंद्रित करते हुए अपने कोड के प्रदर्शन को अधिकतम कर सकते हैं जिसे पूरा करने के लिए आपका प्रोग्राम डिज़ाइन किया गया है।

टीपीएल निम्नलिखित क्षेत्रों में सहायता प्रदान करता है:

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

महत्त्वपूर्ण

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

डेटा समानता

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

टास्क समानांतर लाइब्रेरी कक्षा के माध्यम से डेटा समांतरता का समर्थन करता है System.Threading.Tasks.Parallel । यह वर्ग और लूप के विधि-आधारित समानांतर कार्यान्वयन forforeach प्रदान करता है। आप ए Parallel.For या Parallel.ForEach लूप के लिए लूप लॉजिक लिखते हैं जितना आप एक अनुक्रमिक लूप लिखेंगे। टीपीएल आपके लिए सभी निम्न-स्तरीय कार्य संभालता है।

निम्न कोड उदाहरण एक सरल foreach लूप और इसके समानांतर समकक्ष दिखाता है।


// Sequential version
foreach (var item in sourceCollection)
{
    Process(item);
}

// Parallel equivalent
Parallel.ForEach(sourceCollection, item => Process(item));

TPL डेटा संरचनाओं का एक सेट भी प्रदान करता है जो समवर्ती पहुंच के लिए अनुकूलित होते हैं, जैसे ConcurrentBag, ConcurrentQueue, और ConcurrentDictionary. ये डेटा संरचनाएं आपको स्पष्ट लॉकिंग की आवश्यकता के बिना कई थ्रेड्स से तत्वों को सुरक्षित रूप से जोड़ने, हटाने और एक्सेस करने की अनुमति देती हैं।

निम्न कोड उदाहरण प्रदर्शित करता है कि समानांतर में चल रहे एकाधिक कार्यों से परिणामों को संग्रहीत करने के लिए a ConcurrentBag का उपयोग कैसे करें:


using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        var results = new ConcurrentBag<int>();
        Parallel.For(0, 100, i =>
        {
            // Simulate some work
            Task.Delay(100).Wait();
            results.Add(i);
        });

        Console.WriteLine($"Processed {results.Count} items in parallel.");
    }
}

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

उपयोग Task.WhenAll करें और Task.WhenAny समानांतर में कार्यों को चलाने के लिए

और Task.WhenAllTask.WhenAny विधियां सी # में टास्क समानांतर लाइब्रेरी का हिस्सा हैं। ये विधियाँ आपको समानांतर में कई कार्यों को चलाने और उनके पूरा होने की प्रतीक्षा करने की अनुमति देती हैं।

Task.WhenAll इसका उपयोग तब किया जाता है जब आप आगे बढ़ने से पहले सभी कार्यों के पूरा होने की प्रतीक्षा करना चाहते हैं। यह इनपुट के रूप में कार्यों की एक सरणी लेता है और एक एकल कार्य देता है जो सभी इनपुट कार्यों के पूरा होने का प्रतिनिधित्व करता है। यह तब उपयोगी होता है जब आपके पास कई स्वतंत्र कार्य होते हैं जिन्हें समवर्ती रूप से निष्पादित किया जा सकता है, जैसे कि एक ही समय में कई एपीआई कॉल करना या कई फाइलों को संसाधित करना।

Task.WhenAny इसका उपयोग तब किया जाता है जब आप किसी भी कार्य के पूरा होने की प्रतीक्षा करना चाहते हैं। यह इनपुट के रूप में कार्यों की एक सरणी लेता है और एक कार्य लौटाता है जो पूरा होने वाले पहले कार्य का प्रतिनिधित्व करता है। यह तब उपयोगी होता है जब आप किसी भी कार्य के समाप्त होते ही कुछ क्रिया करना चाहते हैं, उन सभी के पूरा होने की प्रतीक्षा किए बिना।

निम्न कोड उदाहरण प्रदर्शित करता है कि समानांतर में एकाधिक कार्यों को चलाने के लिए उपयोग कैसे करें Task.WhenAll और उनके पूरा होने की प्रतीक्षा करें:


using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.Collections.Generic;

class Program
{
    static async Task Main(string[] args)
    {
        var urls = new List<string>
        {
            "https://example.com",
            "https://example.org",
            "https://example.net"
        };

        var tasks = new List<Task<string>>();

        foreach (var url in urls)
        {
            tasks.Add(FetchDataAsync(url));
        }

        // Wait for all tasks to complete
        var results = await Task.WhenAll(tasks);

        foreach (var result in results)
        {
            Console.WriteLine(result);
        }
    }

    static async Task<string> FetchDataAsync(string url)
    {
        using (var client = new HttpClient())
        {
            return await client.GetStringAsync(url);
        }
    }
}

इस उदाहरण में, FetchDataAsync विधि समानांतर में Task.WhenAllकई URL से डेटा प्राप्त करती है। सभी कार्य पूर्ण होने के बाद परिणाम कंसोल पर मुद्रित किए जाते हैं।

एकाधिक फ़ाइल I/O संचालन समवर्ती रूप से करना

कई मामलों में, फ़ाइल पुनरावृत्ति एक ऑपरेशन है जिसे आसानी से समानांतर किया जा सकता है।

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


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Security;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        try
        {
            TraverseTreeParallelForEach(@"C:\Program Files", (f) =>
            {
                // Exceptions are no-ops.
                try
                {
                    // Do nothing with the data except read it.
                    byte[] data = File.ReadAllBytes(f);
                }
                catch (FileNotFoundException) { }
                catch (IOException) { }
                catch (UnauthorizedAccessException) { }
                catch (SecurityException) { }
                // Display the filename.
                Console.WriteLine(f);
            });
        }
        catch (ArgumentException)
        {
            Console.WriteLine(@"The directory 'C:\Program Files' does not exist.");
        }

        // Keep the console window open.
        Console.ReadKey();
    }

    public static void TraverseTreeParallelForEach(string root, Action<string> action)
    {
        //Count of files traversed and timer for diagnostic output
        int fileCount = 0;
        var sw = Stopwatch.StartNew();

        // Determine whether to parallelize file processing on each folder based on processor count.
        int procCount = Environment.ProcessorCount;

        // Data structure to hold names of subfolders to be examined for files.
        Stack<string> dirs = new Stack<string>();

        if (!Directory.Exists(root))
        {
            throw new ArgumentException(
                "The given root directory doesn't exist.", nameof(root));
        }
        dirs.Push(root);

        while (dirs.Count > 0)
        {
            string currentDir = dirs.Pop();
            string[] subDirs = { };
            string[] files = { };

            try
            {
                subDirs = Directory.GetDirectories(currentDir);
            }
            // Thrown if we do not have discovery permission on the directory.
            catch (UnauthorizedAccessException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            // Thrown if another process has deleted the directory after we retrieved its name.
            catch (DirectoryNotFoundException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }

            try
            {
                files = Directory.GetFiles(currentDir);
            }
            catch (UnauthorizedAccessException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            catch (DirectoryNotFoundException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            catch (IOException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }

            // Execute in parallel if there are enough files in the directory.
            // Otherwise, execute sequentially.Files are opened and processed
            // synchronously but this could be modified to perform async I/O.
            try
            {
                if (files.Length < procCount)
                {
                    foreach (var file in files)
                    {
                        action(file);
                        fileCount++;
                    }
                }
                else
                {
                    Parallel.ForEach(files, () => 0,
                        (file, loopState, localCount) =>
                        {
                            action(file);
                            return (int)++localCount;
                        },
                        (c) =>
                        {
                            Interlocked.Add(ref fileCount, c);
                        });
                }
            }
            catch (AggregateException ae)
            {
                ae.Handle((ex) =>
                {
                    if (ex is UnauthorizedAccessException)
                    {
                        // Here we just output a message and go on.
                        Console.WriteLine(ex.Message);
                        return true;
                    }
                    // Handle other exceptions here if necessary...

                    return false;
                });
            }

            // Push the subdirectories onto the stack for traversal.
            // This could also be done before handing the files.
            foreach (string str in subDirs)
                dirs.Push(str);
        }

        // For diagnostic purposes.
        Console.WriteLine($"Processed {fileCount} files in {sw.ElapsedMilliseconds} milliseconds");
    }
}

इस उदाहरण में, फ़ाइल I/O सिंक्रोनस रूप से किया जाता है। जब आपका कोड बड़ी फ़ाइलों या धीमे नेटवर्क कनेक्शन के साथ काम कर रहा हो, तो फ़ाइलों को अतुल्यकालिक रूप से एक्सेस करना बेहतर हो सकता है। आप समानांतर पुनरावृत्ति के साथ अतुल्यकालिक I/O तकनीकों को जोड़ सकते हैं।

उदाहरण संसाधित फ़ाइलों की कुल संख्या की गणना बनाए रखने के लिए स्थानीय fileCount चर का उपयोग करता है। चर समवर्ती रूप से एकाधिक कार्यों द्वारा पहुँचा जा सकता है, क्योंकि पहुँच विधि कॉल Interlocked.Add द्वारा सिंक्रनाइज़ किया गया है।

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

Summary

इस इकाई ने समांतरता और टास्क पैरेलल लाइब्रेरी (टीपीएल) पर ध्यान केंद्रित किया। इसमें विधि का उपयोग करके समानांतर में अतुल्यकालिक कार्यों को चलाने का तरीका शामिल हैTask.WhenAll, डेटा समानांतरता और Parallel.For विधियों के साथParallel.ForEach, और समवर्ती डेटा संरचनाओं का उपयोग जैसे ConcurrentBag, ConcurrentQueue, और ConcurrentDictionary. सामग्री यह भी प्रदर्शित करती है कि एक साथ एकाधिक फ़ाइल I/O ऑपरेशन कैसे करें।

प्रमुख बिंदु

  • सी # में समानांतर प्रोग्रामिंग एक साथ कई कार्यों को निष्पादित करने की अनुमति देता है।
  • Task कक्षा, async और await कीवर्ड का उपयोग समानांतर प्रोग्रामिंग को लागू करने के लिए किया जाता है।
  • Task.WhenAll विधि का उपयोग आगे बढ़ने से पहले कई कार्यों को पूरा करने की प्रतीक्षा करने के लिए किया जाता है।
  • डेटा समांतरता का उपयोग करके और Parallel.For विधियों को Parallel.ForEach प्राप्त किया जाता है।
  • समवर्ती डेटा संरचनाएं जैसे ConcurrentBag, ConcurrentQueue, और ConcurrentDictionary समवर्ती पहुंच के लिए अनुकूलित हैं।
  • Task.WhenAll और Task.WhenAny विधियां समानांतर में कई कार्यों को चलाने और उनके पूरा होने की प्रतीक्षा करने की अनुमति देती हैं।
  • एकाधिक फ़ाइल I/O ऑपरेशन समवर्ती रूप से किए जा सकते हैं।