Jawaban:
Seperti yang direkomendasikan oleh orang lain, kinerja Interlocked.Increment
akan lebih baik daripada lock()
. Lihat saja IL dan Assembly di mana Anda akan melihat bahwa itu Increment
berubah menjadi pernyataan "kunci bus" dan variabelnya langsung bertambah (x86) atau "ditambahkan" ke (x64).
Pernyataan "kunci bus" ini mengunci bus untuk mencegah CPU lain mengakses bus saat CPU pemanggil melakukan operasinya. Sekarang, lihat lock()
IL pernyataan C # . Di sini Anda akan melihat panggilan Monitor
untuk memulai atau mengakhiri bagian.
Dengan kata lain, lock()
pernyataan .Net melakukan lebih banyak daripada .Net Interlocked.Increment
.
SO, jika semua yang Anda ingin lakukan adalah peningkatan variabel, Interlock.Increment
akan lebih cepat. Tinjau semua metode yang saling terkait untuk melihat berbagai operasi atom yang tersedia dan untuk menemukan yang sesuai dengan kebutuhan Anda. Gunakan lock()
ketika Anda ingin melakukan hal-hal yang lebih kompleks seperti beberapa kenaikan / penurunan yang saling terkait, atau untuk membuat serial akses ke sumber daya yang lebih kompleks daripada bilangan bulat.
Saya sarankan Anda menggunakan kenaikan interlock built in NET di perpustakaan System.Threading.
Kode berikut akan menambah variabel panjang dengan referensi dan sepenuhnya aman untuk thread:
Interlocked.Increment(ref myNum);
Sumber: http://msdn.microsoft.com/en-us/library/dd78zt0c.aspx
Coba dengan Interlocked.Increment
Seperti yang sudah disebutkan digunakan Interlocked.Increment
Contoh kode dari MS:
Contoh berikut menentukan berapa banyak angka acak yang berkisar dari 0 hingga 1.000 diperlukan untuk menghasilkan 1.000 angka acak dengan nilai titik tengah. Untuk melacak jumlah nilai titik tengah, variabel, midpointCount, disetel sama dengan 0 dan bertambah setiap kali generator angka acak mengembalikan nilai titik tengah hingga mencapai 10.000. Karena tiga utas menghasilkan angka acak, metode Penambahan (Int32) dipanggil untuk memastikan bahwa beberapa utas tidak memperbarui midpointCount secara bersamaan. Perhatikan bahwa kunci juga digunakan untuk melindungi generator angka acak, dan bahwa objek CountdownEvent digunakan untuk memastikan bahwa metode Utama tidak menyelesaikan eksekusi sebelum tiga utas.
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
Contoh berikut ini mirip dengan yang sebelumnya, kecuali bahwa ia menggunakan kelas Tugas alih-alih prosedur utas untuk menghasilkan 50.000 bilangan bulat titik tengah acak. Dalam contoh ini, ekspresi lambda menggantikan prosedur thread GenerateNumbers, dan panggilan ke metode Task.WaitAll menghilangkan kebutuhan untuk objek CountdownEvent.
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