Saya tidak dapat menemukan informasi yang cukup tentang ConcurrentDictionary
jenis, jadi saya pikir saya akan menanyakannya di sini.
Saat ini, saya menggunakan a Dictionary
untuk menahan semua pengguna yang diakses secara konstan oleh beberapa utas (dari kumpulan utas, jadi tidak ada jumlah utas yang tepat), dan itu memiliki akses yang disinkronkan.
Saya baru-baru ini menemukan bahwa ada satu set koleksi thread-safe di .NET 4.0, dan tampaknya sangat menyenangkan. Saya bertanya-tanya, apa yang akan menjadi opsi 'lebih efisien dan lebih mudah dikelola', karena saya memiliki pilihan antara memiliki normal Dictionary
dengan akses yang disinkronkan, atau memiliki ConcurrentDictionary
yang sudah aman-thread.
Jawaban:
Koleksi thread-safe vs. koleksi non-threadsafe dapat dilihat dengan cara yang berbeda.
Pertimbangkan toko tanpa petugas, kecuali saat checkout. Anda memiliki banyak masalah jika orang tidak bertindak secara bertanggung jawab. Sebagai contoh, katakanlah seorang pelanggan mengambil kaleng dari piramida-saat petugas sedang membangun piramida, neraka akan pecah. Atau, bagaimana jika dua pelanggan meraih barang yang sama secara bersamaan, siapa yang menang? Apakah akan ada perkelahian? Ini adalah koleksi non-threadsafe. Ada banyak cara untuk menghindari masalah, tetapi mereka semua memerlukan semacam penguncian, atau lebih tepatnya akses eksplisit dalam beberapa cara.
Di sisi lain, pertimbangkan toko dengan pegawai di meja, dan Anda hanya bisa berbelanja melaluinya. Anda mendapatkan antrean, dan meminta item kepadanya, dia membawanya kembali kepada Anda, dan Anda keluar dari barisan. Jika Anda membutuhkan lebih dari satu item, Anda hanya dapat mengambil sebanyak mungkin item pada setiap perjalanan pulang pergi yang Anda ingat, tetapi Anda harus berhati-hati untuk menghindari memonopoli petugas, ini akan membuat pelanggan lain marah di belakang Anda.
Sekarang pertimbangkan ini. Di toko dengan satu petugas, bagaimana jika Anda sampai di garis depan, dan tanyakan kepada petugas "Apakah Anda punya kertas toilet", dan dia berkata "Ya", dan kemudian Anda pergi "Oke, saya Aku akan kembali kepadamu ketika aku tahu berapa yang kubutuhkan ", maka pada saat kau kembali di garis depan, toko tentu saja bisa terjual habis. Skenario ini tidak dicegah oleh koleksi threadsafe.
Kumpulan threadsafe menjamin bahwa struktur data internal valid setiap saat, bahkan jika diakses dari banyak utas.
Koleksi non-threadsafe tidak disertai dengan jaminan semacam itu. Misalnya, jika Anda menambahkan sesuatu ke pohon biner pada satu utas, sedangkan utas lainnya sibuk menyeimbangkan kembali pohon tersebut, tidak ada jaminan item akan ditambahkan, atau bahkan pohon itu masih valid setelahnya, mungkin korup di luar harapan.
Namun, kumpulan threadsafe tidak menjamin bahwa operasi berurutan pada utas semuanya bekerja pada "snapshot" yang sama dari struktur data internal, yang berarti bahwa jika Anda memiliki kode seperti ini:
Anda mungkin mendapatkan NullReferenceException karena inbetween
tree.Count
dantree.First()
, utas lain telah membersihkan node yang tersisa di pohon, yang berartiFirst()
akan kembalinull
.Untuk skenario ini, Anda perlu melihat apakah koleksi tersebut memiliki cara yang aman untuk mendapatkan apa yang Anda inginkan, mungkin Anda perlu menulis ulang kode di atas, atau Anda mungkin perlu mengunci.
sumber
Dictionary
dan menangani penguncian diri sendiri vs menggunakanConcurrentDictionary
tipe yang dibangun pada .NET 4+. Saya sebenarnya sedikit bingung bahwa ini diterima.Anda masih harus sangat berhati-hati saat menggunakan koleksi thread-safe karena thread-safe tidak berarti Anda dapat mengabaikan semua masalah threading. Ketika suatu koleksi mengiklankan dirinya sebagai aman-utas, biasanya itu berarti tetap dalam keadaan konsisten bahkan ketika beberapa utas membaca dan menulis secara bersamaan. Tetapi itu tidak berarti bahwa utas tunggal akan melihat urutan hasil "logis" jika ia memanggil beberapa metode.
Misalnya, jika Anda pertama kali memeriksa apakah kunci ada dan kemudian mendapatkan nilai yang sesuai dengan kunci tersebut, kunci itu mungkin tidak lagi ada bahkan dengan versi ConcurrentDictionary (karena utas lain mungkin telah menghapus kunci). Anda masih perlu menggunakan penguncian dalam kasus ini (atau lebih baik: menggabungkan dua panggilan dengan menggunakan TryGetValue ).
Jadi jangan menggunakannya, tetapi jangan berpikir bahwa itu memberi Anda izin gratis untuk mengabaikan semua masalah konkurensi. Anda masih harus berhati-hati.
sumber
TryGetValue
selalu menjadi bagian dariDictionary
dan selalu menjadi pendekatan yang direkomendasikan. Metode "bersamaan" penting yangConcurrentDictionary
memperkenalkan adalahAddOrUpdate
danGetOrAdd
. Jadi, jawaban yang bagus, tetapi bisa saja mengambil contoh yang lebih baik.Internal ConcurrentDictionary menggunakan kunci terpisah untuk setiap ember hash. Selama Anda hanya menggunakan Tambah / TryGetValue dan metode sejenisnya yang berfungsi pada satu entri, kamus akan berfungsi sebagai struktur data yang hampir bebas kunci dengan masing-masing manfaat kinerja yang manis. OTOH metode enumerasi (termasuk properti Count) mengunci semua ember sekaligus dan karenanya lebih buruk daripada Kamus yang disinkronkan, berdasarkan kinerja.
Saya katakan, cukup gunakan ConcurrentDictionary.
sumber
Saya pikir metode ConcurrentDictionary.GetOrAdd adalah persis apa yang paling dibutuhkan skenario multi-threaded.
sumber
Sudahkah Anda melihat Ekstensi Reaktif untuk. Net 3.5sp1. Menurut Jon Skeet, mereka telah melakukan backport bundel ekstensi paralel dan struktur data bersamaan untuk .Net3.5 sp1.
Ada satu set sampel untuk. Net 4 Beta 2, yang menjelaskan secara cukup baik tentang cara menggunakannya ekstensi paralel.
Saya baru saja menghabiskan minggu lalu menguji ConcurrentDictionary menggunakan 32 utas untuk melakukan I / O. Tampaknya berfungsi seperti yang diiklankan, yang akan menunjukkan sejumlah besar pengujian telah dimasukkan ke dalamnya.
Edit : .NET 4 ConcurrentDictionary dan pola.
Microsoft telah merilis pdf yang disebut Pola Pemrograman Paralell. Benar-benar layak untuk diunduh karena dijelaskan dalam detail yang sangat bagus pola yang tepat untuk digunakan untuk .Net 4 Ekstensi bersamaan dan pola anti yang harus dihindari. Ini dia.
sumber
Pada dasarnya Anda ingin menggunakan ConcurrentDictionary baru. Tepat di luar kotak Anda harus menulis lebih sedikit kode untuk membuat program yang aman.
sumber
Ini
ConcurrentDictionary
adalah pilihan yang bagus jika memenuhi semua kebutuhan keselamatan benang Anda. Jika tidak, dengan kata lain Anda melakukan sesuatu yang sedikit rumit,Dictionary
+ yang normallock
mungkin merupakan pilihan yang lebih baik. Misalnya, katakanlah Anda menambahkan beberapa pesanan ke dalam kamus, dan Anda ingin terus memperbarui jumlah total pesanan. Anda dapat menulis kode seperti ini:Kode ini tidak aman untuk thread. Beberapa utas yang memperbarui
_totalAmount
bidang dapat menyebabkannya dalam kondisi rusak. Jadi, Anda dapat mencoba melindunginya denganlock
:Kode ini "lebih aman", tetapi masih belum aman. Tidak ada jaminan bahwa
_totalAmount
konsisten dengan entri dalam kamus. Utas lain mungkin mencoba membaca nilai-nilai ini, untuk memperbarui elemen UI:The
totalAmount
mungkin tidak sesuai dengan hitungan perintah dalam kamus. Statistik yang ditampilkan mungkin salah. Pada titik ini Anda akan menyadari bahwa Anda harus memperluaslock
perlindungan untuk memasukkan pembaruan kamus:Kode ini sangat aman, tetapi semua manfaat menggunakan a
ConcurrentDictionary
hilang.Dictionary
, karena penguncian internal di dalamConcurrentDictionary
sekarang boros dan berlebihan.TryAdd
?,AddOrUpdate
?).Jadi saran saya adalah: mulailah dengan tanda
Dictionary
+lock
, dan simpan opsi untuk meningkatkan versi nantiConcurrentDictionary
sebagai optimasi kinerja, jika opsi ini benar-benar layak. Dalam banyak kasus itu tidak akan terjadi.sumber
Kami telah menggunakan ConcurrentDictionary untuk koleksi cache, yang diisi ulang setiap 1 jam dan kemudian dibaca oleh banyak utas klien, mirip dengan solusi untuk Apakah ini contoh utas aman? pertanyaan.
Kami menemukan, bahwa mengubahnya menjadi ReadOnlyDictionary meningkatkan kinerja secara keseluruhan.
sumber