Saya telah bereksperimen dengan multi threading dan pemrosesan paralel dan saya membutuhkan penghitung untuk melakukan beberapa penghitungan dasar dan analisis statistik dari kecepatan pemrosesan. Untuk menghindari masalah dengan penggunaan kelas saya secara bersamaan, saya telah menggunakan pernyataan kunci pada variabel pribadi di kelas saya:
private object mutex = new object();
public void Count(int amount)
{
lock(mutex)
{
done += amount;
}
}
Tapi saya bertanya-tanya ... seberapa mahal mengunci variabel? Apa dampak negatifnya terhadap kinerja?
c#
.net
multithreading
locking
parallel-processing
Kees C. Bakker
sumber
sumber
Jawaban:
Berikut adalah artikel yang membahas biayanya. Jawaban singkatnya adalah 50ns.
sumber
lock
lebih dari yang Anda khawatirkan tentang biaya menggunakan variabel.Jawaban teknisnya adalah bahwa ini tidak mungkin untuk dihitung, hal ini sangat bergantung pada status buffer tulis kembali memori CPU dan berapa banyak data yang dikumpulkan prefetcher harus dibuang dan dibaca ulang. Keduanya sangat non-deterministik. Saya menggunakan 150 siklus CPU sebagai perkiraan belakang amplop yang menghindari kekecewaan besar.
Jawaban praktis adalah bahwa hal itu waaaay lebih murah daripada jumlah waktu Anda akan membakar pada debugging kode Anda ketika Anda berpikir Anda dapat melewatkan kunci.
Untuk mendapatkan angka pasti, Anda harus mengukur. Visual Studio memiliki penganalisis konkurensi apik yang tersedia sebagai ekstensi.
sumber
Bacaan lebih lanjut:
Saya ingin menyajikan beberapa artikel saya, yang tertarik pada sinkronisasi umum primitif dan mereka menggali Monitor, perilaku pernyataan kunci C #, properti, dan biaya tergantung pada skenario yang berbeda dan jumlah utas. Ini secara khusus tertarik tentang pemborosan CPU dan periode throughput untuk memahami berapa banyak pekerjaan yang dapat didorong dalam berbagai skenario:
https://www.codeproject.com/Articles/1236238/Unified-Concurrency-I-Introduction https://www.codeproject.com/Articles/1237518/Unified-Concurrency-II-benchmarking-methodologies https: // www. codeproject.com/Articles/1242156/Unified-Concurrency-III-cross-benchmarking
Jawaban asli:
Oh sayang!
Tampaknya jawaban yang benar yang ditandai di sini sebagai JAWABAN pada dasarnya salah! Saya ingin meminta penulis jawabannya, dengan hormat, untuk membaca artikel yang ditautkan sampai akhir. artikel
Penulis artikel dari tahun 2003 pasal itu mengukur pada mesin Dual Core saja dan dalam kasus pengukuran pertama, ia diukur mengunci dengan thread tunggal hanya dan hasilnya adalah sekitar 50ns per akses kunci.
Ia tidak mengatakan apa-apa tentang kunci di lingkungan bersamaan. Jadi kita harus melanjutkan membaca artikel dan di paruh kedua, penulis mengukur skenario penguncian dengan dua dan tiga utas, yang mendekati tingkat konkurensi prosesor saat ini.
Jadi penulis mengatakan, bahwa dengan dua utas pada Dual Core, kuncinya berharga 120ns, dan dengan 3 utas harganya menjadi 180ns. Jadi tampaknya jelas bergantung pada jumlah utas yang mengakses kunci secara bersamaan.
Jadi sederhana, bukan 50 ns kecuali jika itu adalah utas tunggal, di mana kuncinya menjadi tidak berguna.
Masalah lain yang perlu dipertimbangkan adalah bahwa waktu tersebut diukur sebagai waktu rata - rata !
Jika waktu iterasi akan diukur, akan ada waktu antara 1ms hingga 20ms, hanya karena mayoritas cepat, tetapi beberapa utas akan menunggu waktu prosesor dan bahkan menimbulkan penundaan milidetik.
Ini adalah berita buruk untuk semua jenis aplikasi yang membutuhkan throughput tinggi, latensi rendah.
Dan masalah terakhir yang perlu dipertimbangkan adalah bahwa mungkin ada operasi yang lebih lambat di dalam kunci dan seringkali demikian. Semakin lama blok kode dieksekusi di dalam kunci, semakin tinggi pertikaian dan penundaan meningkat setinggi langit.
Harap pertimbangkan, bahwa lebih dari satu dekade telah berlalu dari tahun 2003, itu adalah beberapa generasi prosesor yang dirancang khusus untuk berjalan secara penuh secara bersamaan dan penguncian sangat merugikan kinerja mereka.
sumber
Ini tidak menjawab pertanyaan Anda tentang kinerja, tetapi saya dapat mengatakan bahwa .NET Framework memang menawarkan
Interlocked.Add
metode yang memungkinkan Anda menambahkan Andaamount
kedone
anggota Anda tanpa mengunci objek lain secara manual.sumber
lock
(Monitor.Enter / Exit) sangat murah, lebih murah daripada alternatif seperti Waithandle atau Mutex.Tetapi bagaimana jika (sedikit) lambat, apakah Anda lebih suka program yang cepat dengan hasil yang salah?
sumber
Biaya untuk mengunci dalam loop yang rapat, dibandingkan dengan alternatif tanpa kunci, sangat besar. Anda dapat melakukan loop berkali-kali dan masih lebih efisien daripada kunci. Itulah mengapa antrian bebas kunci sangat efisien.
Keluaran:
sumber
Ada beberapa cara berbeda untuk mendefinisikan "biaya". Ada biaya overhead yang sebenarnya untuk mendapatkan dan melepaskan kunci; seperti yang ditulis Jake, hal itu dapat diabaikan kecuali operasi ini dilakukan jutaan kali.
Yang lebih relevan adalah efeknya pada aliran eksekusi. Kode ini hanya dapat dimasukkan oleh satu utas dalam satu waktu. Jika Anda memiliki 5 utas yang melakukan operasi ini secara teratur, 4 di antaranya akan menunggu kunci dilepaskan, dan kemudian menjadi utas pertama yang dijadwalkan untuk memasukkan potongan kode itu setelah kunci itu dilepaskan. Jadi, algoritme Anda akan sangat terpengaruh. Seberapa banyak tergantung pada algoritme dan seberapa sering operasi dipanggil .. Anda tidak dapat benar-benar menghindarinya tanpa memperkenalkan kondisi balapan, tetapi Anda dapat memperbaikinya dengan meminimalkan jumlah panggilan ke kode yang terkunci.
sumber