21 Haziran 2015 Pazar

Concurrent Collections

Not 1:  Java'da Concurrent Kuyruk konusu geniş olduğu için ayrı bir yazı olarak buraya taşıdım.
Not 2: C#'ta Concurrent Kuyruk konusu geniş olduğu için ayrı bir yazı olarak buraya taşıdım.
Not 3: Actor Model'de shared state olmaz.

Kuyruk Teorisi
Kuyruk teorisi veri yapısı ile ilgili değil. Ancak dolaylı olarak kuyruğun ne kadar büyük olması gerektiği ve bekleme süresini matematiksel olarak gösterdiği için bilinmesi faydalı. M/M/1 kuyruğu bu teoride kullanılan basit bir kuyruk.

Amdalh Kanunu
Bu kanunda concurrent programlama modeline geçilse bile hızın paralelleştirilemeyen kod parçasına bağımlı olduğu belirtilmiş.Örneğin sadece %50'si paralelleştirilebilen bir kod parçasına 16 işlemci ekleyerek 2 kat hızlanma elde edilir. Bundan sonra eklenen işlemci sayısının bir etkisi olmaz.

Concurrent Collections
Aşağıda çeşitli dillerde gördüğüm concurrent veri yapıları ile ilgili aldığım notlar var. Öncelikle ACE, Java ve C# arasındaki temel felsefe farkına dikkat etmek lazım.

ACE kütüphanesi, strategy örüntüsünü izleyerek veri yapısına dışarıdan kilitleme mekanizmasının geçilmesi felsefesini benimsemiş. Böylece aynı veri yapısı, kullanıcının isteğine göre thread-safe olarak veya olmayarak kullanılabiliyor.

Java ve C# ise veri yapılarının thread-safe olan ve olmayan 2 farklı sınıfını sunuyor.

ACE ACE_Map_Manager
Örneği buradan aldım.

//Eğer istenirse
//ACE_Null_Mutex
//ACE_Thread_Mutex
//ACE_Recursive_Thread_Mutex
//ACE_RW_Mutex kullanılabilir
typedef ACE_Map_Manager<unsigned long, std::string, ACE_Thread_Mutex> StringMap; 
StringMap m_MapInstance;

typedef StringMap::lock_type ACE_MAP_LOCK_TYPE;
//Create a guard
ACE_Guard<ACE_MAP_LOCK_TYPE> l(m_MapInstance.mutex());
for(StringMap::iterator it = m_MapInstance.begin(), end = m_MapInstance.end(); it!=end; ++it)
{
    const std::string & strContent = (*it).int_id_;
    const unsigned long & ulID = (*it).ext_id_;
    //do something with the element here
}
C# Partitioner
Range Partitioning, Chunk Partitioning algoritmaları var.

EnumerablePartitionerOptions sınıfı

NoBuffering seçeneği
Eğer listedeki elemanları teker teker thread'lere dağıtmak istersek aşağıdaki gibi yapabiliriz.
List<string> _files = new List<string>();
Parallel.ForEach(Partitioner.Create(_files, EnumerablePartitionerOptions.NoBuffering),
                new ParallelOptions
                {
                    MaxDegreeOfParallelism = 5 //limit number of parallel threads
                },
                (file, loopstate, index) =>
                {
                    if (token.IsCancellationRequested)
                        return;
                    //do work...
                });


C# ConcurrentBag
Bu sınıf bag olduğu için sırasız yani unordered bir veri yapısı. Object Pool gibi sıranın önemli olmadığı veri yapılarında kullanmak için ideal. Sırasız çalıştığını aşağıdaki şekilde görebiliriz. Bu sınıf sanırım Java'daki ConcurrentHashMultiSet'e denk geliyor.
image

Add() ve TryTake() bu sınıfın en önemli metodları.

Örnek:
var stringResult = new ConcurrentBag<string>();
stringResult.Add ("line");
string item;
stringResult.TryTake (out item);//Bag'den bir eleman çek
C# ConcurrentDictionary
ConcurrentDictionary yazısına taşıdım.

Java ConcurrentHashMap
ConcurrentHashMap yazısına taşıdım.

Java ConcurrentSkipList
ConcurrentSkipListSet yazısına taşıdım.

Java ConcurrentSkipListMap
ConcurrentSkipListMap yazısına taşıdım


1 yorum: