সি # থ্রেড নিরাপদ দ্রুত (ইস্ট) কাউন্টার


147

সেরা সম্ভাব্য পারফরম্যান্স সহ সি # তে একটি থ্রেড নিরাপদ কাউন্টার পাওয়ার উপায় কী?

এটি এটি হিসাবে এটি সহজ:

public static long GetNextValue()
{
    long result;
    lock (LOCK)
    {
        result = COUNTER++;
    }
    return result;
}

তবে কি আরও দ্রুত বিকল্প রয়েছে?

উত্তর:



108

অন্যদের দ্বারা প্রস্তাবিত হিসাবে, এর Interlocked.Incrementচেয়ে ভাল পারফরম্যান্স থাকবে lock()। কেবলমাত্র আইএল এবং অ্যাসেমব্লির দিকে একবার নজর দিন যেখানে আপনি দেখতে পাবেন যে Incrementএটি একটি "বাস লক" বিবৃতিতে পরিণত হয় এবং এর ভেরিয়েবলটি সরাসরি বর্ধিত হয় (x86) বা "x64" এ "যুক্ত"।

এই "বাস লক" বিবৃতিটি অন্য সিপিইউটিকে বাসে প্রবেশ করা থেকে বিরত রাখতে বাসটিকে লক করেছে যখন কলিং সিপিইউ তার কার্যক্রম পরিচালনা করে। এখন, সি # lock()স্টেটমেন্টের আইএল একবার দেখুন। এখানে Monitorকোনও বিভাগ শুরু বা শেষ করার জন্য আপনি কলগুলি দেখতে পাবেন ।

অন্য কথায় ,। নেট lock()স্টেটমেন্ট নেট থেকে অনেক বেশি করছে Interlocked.Increment

সুতরাং, আপনি যা করতে চান তা যদি ভেরিয়েবলের বর্ধিত হয় Interlock.Incrementতবে দ্রুত হবে। উপলব্ধ বিভিন্ন পারমাণবিক ক্রিয়াকলাপগুলি দেখার জন্য এবং আপনার প্রয়োজন অনুসারে সেগুলি অনুসন্ধান করার জন্য ইন্টারলকযুক্ত সমস্ত পদ্ধতির পর্যালোচনা করুন। lock()আপনি যখন একাধিক আন্ত-সম্পর্কিত বৃদ্ধি বা হ্রাসের মতো আরও জটিল কিছু করতে চান বা সংখ্যার চেয়ে জটিল জটিল সংস্থাগুলিতে অ্যাক্সেসকে সিরিয়ালাইজ করতে চান তখন ব্যবহার করুন ।


3
বাস্তবায়ন বিশদ জন্য -1। এটি সত্য যে লকিং কোনও পারমাণবিক অপের চেয়ে ধীর গতিযুক্ত, তবে আইএলের সাথে এর কোনও যোগসূত্র নেই। এই ফাংশন কলগুলি যদি তাদের শব্দার্থবিজ্ঞানের জন্য না হয় তবে পারমাণবিক অপেক্ষার চেয়ে দ্রুততর হবে, যা অন্তর্নিহিতভাবে আইএল-র প্রয়োজন হয় না।
কুকুরছানা

33

আমি আপনাকে পরামর্শ দিচ্ছি যে আপনি .NET এর অন্তর্লক ইনক্রিমেন্টে সিস্টেম.ত্রে পাঠ্য লাইব্রেরিতে অন্তর্নির্মিত ব্যবহার করুন।

নিম্নলিখিত কোডটি রেফারেন্স দ্বারা একটি দীর্ঘ পরিবর্তনশীল বৃদ্ধি করবে এবং সম্পূর্ণ থ্রেড নিরাপদ:

Interlocked.Increment(ref myNum);

সূত্র: http://msdn.microsoft.com/en-us/library/dd78zt0c.aspx



1

ইতিমধ্যে উল্লিখিত ব্যবহার হিসাবে Interlocked.Increment

এমএস থেকে কোড উদাহরণ:

নিম্নলিখিত উদাহরণটি নির্ধারণ করে যে 0 থেকে 1,000 অবধি কতগুলি এলোমেলো সংখ্যাগুলি মিডপয়েন্ট মান সহ 1,000 র্যান্ডম সংখ্যা উত্পন্ন করতে প্রয়োজনীয়। মিডপয়েন্ট মানগুলির সংখ্যার উপর নজর রাখতে, একটি ভেরিয়েবল, মিডপয়েন্টকউন্ট, 0 এর সমান সেট করা হয় এবং প্রতিবার এলোমেলো সংখ্যা জেনারেটর 10,000 পয়েন্ট না হওয়া পর্যন্ত একটি মিডপয়েন্ট মান প্রদান করে। যেহেতু তিনটি থ্রেড এলোমেলো সংখ্যা তৈরি করে, একাধিক থ্রেড মিডপয়েন্টকন্ট একযোগে আপডেট না করে তা নিশ্চিত করার জন্য বর্ধন (ইন্ট 32) পদ্ধতিটি কল করা হয়। নোট করুন যে এলোমেলো সংখ্যা জেনারেটর সুরক্ষার জন্য একটি লকও ব্যবহৃত হয় এবং একটি কাউন্টডাউনএভেন্ট অবজেক্ট তিনটি থ্রেডের আগেই মেইন পদ্ধতিটি কার্যকর করা শেষ করে না তা নিশ্চিত করতে ব্যবহৃত হয়।

using System;
using System.Threading;

public class Example
{
   const int LOWERBOUND = 0;
   const int UPPERBOUND = 1001;

   static Object lockObj = new Object();
   static Random rnd = new Random();
   static CountdownEvent cte;

   static int totalCount = 0;
   static int totalMidpoint = 0;
   static int midpointCount = 0;

   public static void Main()
   {
      cte = new CountdownEvent(1);
      // Start three threads. 
      for (int ctr = 0; ctr <= 2; ctr++) {
         cte.AddCount();
         Thread th = new Thread(GenerateNumbers);
         th.Name = "Thread" + ctr.ToString();
         th.Start();
      }
      cte.Signal();
      cte.Wait();
      Console.WriteLine();
      Console.WriteLine("Total midpoint values:  {0,10:N0} ({1:P3})",
                        totalMidpoint, totalMidpoint/((double)totalCount));
      Console.WriteLine("Total number of values: {0,10:N0}", 
                        totalCount);                  
   }

   private static void GenerateNumbers()
   {
      int midpoint = (UPPERBOUND - LOWERBOUND) / 2;
      int value = 0;
      int total = 0;
      int midpt = 0;

      do {
         lock (lockObj) {
            value = rnd.Next(LOWERBOUND, UPPERBOUND);
         }
         if (value == midpoint) { 
            Interlocked.Increment(ref midpointCount);
            midpt++;
         }
         total++;    
      } while (midpointCount < 10000);

      Interlocked.Add(ref totalCount, total);
      Interlocked.Add(ref totalMidpoint, midpt);

      string s = String.Format("Thread {0}:\n", Thread.CurrentThread.Name) +
                 String.Format("   Random Numbers: {0:N0}\n", total) + 
                 String.Format("   Midpoint values: {0:N0} ({1:P3})", midpt, 
                               ((double) midpt)/total);
      Console.WriteLine(s);
      cte.Signal();
   }
}
// The example displays output like the following:
//       Thread Thread2:
//          Random Numbers: 2,776,674
//          Midpoint values: 2,773 (0.100 %)
//       Thread Thread1:
//          Random Numbers: 4,876,100
//          Midpoint values: 4,873 (0.100 %)
//       Thread Thread0:
//          Random Numbers: 2,312,310
//          Midpoint values: 2,354 (0.102 %)
//       
//       Total midpoint values:      10,000 (0.100 %)
//       Total number of values:  9,965,084

নিম্নলিখিত উদাহরণটি পূর্ববর্তীটির মতোই, এটি 50,000 এলোমেলো মিডপয়েন্ট ইন্টিজার উত্পন্ন করার জন্য কোনও থ্রেড পদ্ধতির পরিবর্তে টাস্ক ক্লাস ব্যবহার করে। এই উদাহরণে, একটি ল্যাম্বডা এক্সপ্রেশন জেনারেট নাম্বার থ্রেড পদ্ধতিটি প্রতিস্থাপন করে এবং টাস্ক.ওয়েটএল পদ্ধতিতে কলটি কাউন্টডাউনভেন্ট অবজেক্টের প্রয়োজনীয়তা দূর করে।

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

public class Example
{
   const int LOWERBOUND = 0;
   const int UPPERBOUND = 1001;

   static Object lockObj = new Object();
   static Random rnd = new Random();

   static int totalCount = 0;
   static int totalMidpoint = 0;
   static int midpointCount = 0;

   public static void Main()
   {
      List<Task> tasks = new List<Task>();
      // Start three tasks. 
      for (int ctr = 0; ctr <= 2; ctr++) 
         tasks.Add(Task.Run( () => { int midpoint = (UPPERBOUND - LOWERBOUND) / 2;
                                     int value = 0;
                                     int total = 0;
                                     int midpt = 0;

                                     do {
                                        lock (lockObj) {
                                           value = rnd.Next(LOWERBOUND, UPPERBOUND);
                                        }
                                        if (value == midpoint) { 
                                           Interlocked.Increment(ref midpointCount);
                                           midpt++;
                                        }
                                        total++;    
                                     } while (midpointCount < 50000);

                                     Interlocked.Add(ref totalCount, total);
                                     Interlocked.Add(ref totalMidpoint, midpt);

                                     string s = String.Format("Task {0}:\n", Task.CurrentId) +
                                                String.Format("   Random Numbers: {0:N0}\n", total) + 
                                                String.Format("   Midpoint values: {0:N0} ({1:P3})", midpt, 
                                                              ((double) midpt)/total);
                                     Console.WriteLine(s); } ));

      Task.WaitAll(tasks.ToArray());
      Console.WriteLine();
      Console.WriteLine("Total midpoint values:  {0,10:N0} ({1:P3})",
                        totalMidpoint, totalMidpoint/((double)totalCount));
      Console.WriteLine("Total number of values: {0,10:N0}", 
                        totalCount);                  
   }
}
// The example displays output like the following:
//       Task 3:
//          Random Numbers: 10,855,250
//          Midpoint values: 10,823 (0.100 %)
//       Task 1:
//          Random Numbers: 15,243,703
//          Midpoint values: 15,110 (0.099 %)
//       Task 2:
//          Random Numbers: 24,107,425
//          Midpoint values: 24,067 (0.100 %)
//       
//       Total midpoint values:      50,000 (0.100 %)
//       Total number of values: 50,206,378

https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked.increment?view=netcore-3.0

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.