जवाबों:
जैसा कि दूसरों ने सुझाया है, इससे Interlocked.Increment
बेहतर प्रदर्शन होगा lock()
। बस IL और असेंबली पर एक नज़र डालें जहां आप देखेंगे कि Increment
"बस लॉक" स्टेटमेंट में बदल जाता है और इसका वेरिएबल सीधे (x86) या "जोड़ा गया" (x64) हो जाता है।
यह "बस लॉक" स्टेटमेंट किसी अन्य सीपीयू को बस तक पहुंचने से रोकने के लिए बस को लॉक करता है जबकि कॉलिंग सीपीयू अपना ऑपरेशन करता है। अब, C # lock()
स्टेटमेंट के IL पर एक नज़र डालें । यहां आपको Monitor
किसी अनुभाग को शुरू करने या समाप्त करने के लिए कॉल दिखाई देगी ।
दूसरे शब्दों में, .Net lock()
बयान .Net की तुलना में बहुत अधिक कर रहा है Interlocked.Increment
।
एसओ, यदि आप सब करना चाहते हैं तो एक परिवर्ती वृद्धि Interlock.Increment
होगी , और तेज़ होगी। उपलब्ध विभिन्न परमाणु संचालन को देखने के लिए और अपनी आवश्यकताओं के अनुरूप उन लोगों को खोजने के लिए सभी इंटरलॉक की गई विधियों की समीक्षा करें। का प्रयोग करें lock()
जब आप उन संसाधनों पूर्णांकों की तुलना में अधिक जटिल हैं करने के लिए कई परस्पर संबंधित वेतन वृद्धि / decrements, या क्रमानुसार करने पहुँच की तरह अधिक जटिल चीज़ों करना चाहते हैं।
मेरा सुझाव है कि आप System.Threading पुस्तकालय में .NET के इंटरलॉक वेतन वृद्धि का उपयोग करें।
निम्नलिखित कोड संदर्भ द्वारा एक लंबा चर बढ़ाएगा और पूरी तरह से सुरक्षित है:
Interlocked.Increment(ref myNum);
स्रोत: http://msdn.microsoft.com/en-us/library/dd78zt0c.aspx
Interlocked.Increment के साथ प्रयास करें
जैसा कि पहले ही उल्लेख किया गया है Interlocked.Increment
MS से कोड उदाहरण:
निम्न उदाहरण से पता चलता है कि 0 से 1,000 तक की कितनी यादृच्छिक संख्याओं को एक मिडपॉइंट मान के साथ 1,000 यादृच्छिक संख्याएं उत्पन्न करने के लिए आवश्यक है। मिडपॉइंट मानों की संख्या पर नज़र रखने के लिए, एक चर, मिडपॉइंटकाउंट, 0 के बराबर सेट किया गया है और हर बार वृद्धि होने पर यादृच्छिक संख्या जनरेटर एक मिडपॉइंट मान लौटाता है जब तक कि यह 10,000 तक नहीं पहुंचता। क्योंकि तीन थ्रेड यादृच्छिक संख्याएँ उत्पन्न करते हैं, इंक्रीमेंट (Int32) विधि को यह सुनिश्चित करने के लिए कहा जाता है कि एकाधिक थ्रेड्स मध्य बिंदु को समवर्ती रूप से अपडेट नहीं करते हैं। ध्यान दें कि यादृच्छिक संख्या जनरेटर की सुरक्षा के लिए एक लॉक का भी उपयोग किया जाता है, और यह सुनिश्चित करने के लिए कि एक उलटी गिनती वस्तु का उपयोग किया जाता है ताकि मुख्य विधि तीन थ्रेड्स से पहले निष्पादन को समाप्त न करें।
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 यादृच्छिक मिडपॉइंट पूर्णांकों को उत्पन्न करने के लिए थ्रेड प्रक्रिया के बजाय टास्क क्लास का उपयोग करता है। इस उदाहरण में, एक लैम्ब्डा अभिव्यक्ति GenerateNumbers थ्रेड प्रक्रिया को प्रतिस्थापित करता है, और टास्क को कॉल करता है। WitAll विधि काउंटडाउनवेंट ऑब्जेक्ट की आवश्यकता को समाप्त करता है।
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