Share via


İş parçacığı güvenli koleksiyon ne zaman kullanılır?

.NET Framework 4, çok iş parçacıklı ekleme ve kaldırma işlemlerini desteklemek için özel olarak tasarlanmış beş koleksiyon türü kullanıma sunulmuştur. İş parçacığı güvenliği elde etmek için, bu türlerde çeşitli verimli kilitleme ve kilitlemesiz eşitleme mekanizmaları kullanılır. Eşitleme işlemine ek yük ekler. Ek yük miktarı, kullanılan eşitleme türüne, gerçekleştirilen işlemlerin türüne ve koleksiyona eşzamanlı olarak erişmeye çalışan iş parçacığı sayısı gibi diğer faktörlere bağlıdır.

Bazı senaryolarda eşitleme yükü göz ardı edilir ve çok iş parçacıklı türün, bir dış kilit tarafından korunduğunda iş parçacığı güvenli olmayan eşdeğerinden çok daha hızlı performans göstermesini ve çok daha iyi ölçeklendirmesini sağlar. Diğer senaryolarda ek yük, iş parçacığı güvenli türünün gerçekleştirmesine ve türün dışarıdan kilitli, iş parçacığı güvenli olmayan sürümünden daha yavaş bir şekilde gerçekleştirilip ölçeklendirilmesine neden olabilir.

Aşağıdaki bölümlerde, okuma ve yazma işlemlerinin çevresinde kullanıcı tarafından sağlanan bir kilit bulunan iş parçacığı güvenli olmayan eşdeğerine kıyasla iş parçacığı güvenli bir koleksiyonun ne zaman kullanılacağı hakkında genel yönergeler sağlanır. Performans birçok faktöre bağlı olarak farklılık gösterebileceğinden, kılavuz belirli değildir ve her koşulda geçerli olmayabilir. Performans çok önemliyse, kullanılacak koleksiyon türünü belirlemenin en iyi yolu temsili bilgisayar yapılandırmalarına ve yüklemelerine göre performansı ölçmektir. Bu belgede aşağıdaki terimler kullanılır:

Saf üretici-tüketici senaryosu
Belirli bir iş parçacığı öğeleri ekliyor veya kaldırıyor, ancak ikisini birden eklenmiyor.

Karma üretici-tüketici senaryosu
Belirli bir iş parçacığı hem öğe ekliyor hem de kaldırıyor.

Speedup
Aynı senaryoda başka bir türe göre daha hızlı algoritmik performans.

Ölçeklenebilirlik
Bilgisayardaki çekirdek sayısıyla orantılı performans artışı. Ölçeklendirilen bir algoritma, sekiz çekirdekte iki çekirdekten daha hızlı performans gösterir.

ConcurrentQueue(T) ile Kuyruk(T) karşılaştırması

Her öğenin işlem süresinin çok küçük olduğu (birkaç yönerge) System.Collections.Concurrent.ConcurrentQueue<T> saf üretici-tüketici senaryolarında, dış kilidi olan bir System.Collections.Generic.Queue<T> öğeye göre mütevazı performans avantajları sunabilir. Bu senaryoda, ConcurrentQueue<T> ayrılmış bir iş parçacığı kuyruğa alırken ve bir ayrılmış iş parçacığı kuyruğa almadığında en iyi performansı gösterir. Bu kuralı zorunlu kılmazsanız, Queue<T> birden çok çekirdeği olan bilgisayarlardan biraz daha ConcurrentQueue<T> hızlı bile çalışabilir.

İşleme süresi yaklaşık 500 FLOPS (kayan nokta işlemleri) veya daha fazla olduğunda, iki iş parçacığı kuralı için ConcurrentQueue<T>geçerli değildir ve daha sonra çok iyi ölçeklenebilirliğe sahiptir. Queue<T> bu senaryoda iyi ölçeklendirilmemektedir.

Karma üretici-tüketici senaryolarında, işlem süresi çok küçük olduğunda, dış kilidi olan bir Queue<T> , olduğundan ConcurrentQueue<T> daha iyi ölçeklendirilir. Ancak, işleme süresi yaklaşık 500 FLOPS veya daha fazla olduğunda, ConcurrentQueue<T> ölçek daha iyi olur.

ConcurrentStack ve Stack karşılaştırması

Saf üretici-tüketici senaryolarında, işleme süresi çok küçük System.Collections.Concurrent.ConcurrentStack<T> olduğunda ve System.Collections.Generic.Stack<T> dış kilidi olan bir büyük olasılıkla bir ayrılmış gönderme iş parçacığı ve bir ayrılmış haşhaş iş parçacığı ile yaklaşık aynı performansı gösterir. Ancak, iş parçacığı sayısı arttıkça her iki tür de artan çekişme nedeniyle yavaşlar ve Stack<T> değerinden ConcurrentStack<T>daha iyi performans gösterebilir. İşleme süresi yaklaşık 500 FLOPS veya daha fazla olduğunda, her iki tür de yaklaşık aynı hızda ölçeklendirilir.

Karma üretici-tüketici senaryolarında hem ConcurrentStack<T> küçük hem de büyük iş yükleri için daha hızlıdır.

ve TryPopRange kullanımı PushRange erişim sürelerini büyük ölçüde hızlandırabilir.

ConcurrentDictionary ile Sözlük karşılaştırması

Genel olarak, birden çok iş parçacığından anahtarları veya değerleri eşzamanlı olarak ekleyip güncelleştirdiğiniz herhangi bir senaryoda kullanın System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue> . Sık güncelleştirmeler ve nispeten az okuma içeren senaryolarda, ConcurrentDictionary<TKey,TValue> genellikle mütevazı avantajlar sunar. Çok sayıda okuma ve çok sayıda güncelleştirme içeren senaryolarda, ConcurrentDictionary<TKey,TValue> genel olarak herhangi bir sayıda çekirdeği olan bilgisayarlarda önemli ölçüde daha hızlıdır.

Sık güncelleştirmeler içeren senaryolarda, içindeki eşzamanlılık ConcurrentDictionary<TKey,TValue> derecesini artırabilir ve ardından daha fazla çekirdeği olan bilgisayarlarda performansın artıp artmadığını görmek için ölçebilirsiniz. Eşzamanlılık düzeyini değiştirirseniz, genel işlemlerden mümkün olduğunca kaçının.

Yalnızca anahtar veya değerleri okuyorsanız, Dictionary<TKey,TValue> sözlüğün herhangi bir iş parçacığı tarafından değiştirilmemesi durumunda eşitleme gerekmediğinden daha hızlıdır.

Concurrentbag

Saf üretici-tüketici senaryolarında, System.Collections.Concurrent.ConcurrentBag<T> büyük olasılıkla diğer eşzamanlı koleksiyon türlerinden daha yavaş performans gösterecektir.

Karma üretici-tüketici senaryolarında genellikle ConcurrentBag<T> hem büyük hem de küçük iş yükleri için diğer tüm eşzamanlı koleksiyon türlerinden çok daha hızlı ve daha ölçeklenebilirdir.

BlockingCollection

Sınırlayıcı ve engelleme semantiği gerektiğinde, System.Collections.Concurrent.BlockingCollection<T> büyük olasılıkla herhangi bir özel uygulamadan daha hızlı performans gösterir. Ayrıca zengin iptal, numaralandırma ve özel durum işlemeyi destekler.

Ayrıca bkz.