PLINQ Nedir? Kullanılması ve Kullanılmaması Gereken Yerler?

recep orhan
3 min readNov 2, 2021

PLINQ Nedir?

PLINQ, çok işlemcili bilgisayarlarda LINQ sorgularının hızını arttırmak için kullanılmaktadır. LINQ sorgularına çok benzemektedir. Aralarındaki temel fark LINQ’te koleksiyona ait tüm işler tek thread ile yapılırken PLINQ memorydeki koleksiyonu önce parçalara ayırır, sonrasında her parçayı bir iş thread’ine atayarak sonuçları üretir. Bu sayede sonuçları çok hızlı bir şekilde getirir.

var numberList= Enumerable.Range(1, 100).ToList();var queryA = from num in numberList 
where num % 2 == 0
select num;

1 den 100 e kadar olan koleksiyonumuzda çift sayıların listesini aldığımız linq sorgusu yukarıdaki gibidir.

Koleksiyonun sonuna eklenen AsParallel() methodu ile PLINQ kullanılır.

var numberList= Enumerable.Range(1, 100).ToList();var queryA = from num in numberList.AsParallel() 
where num % 2 == 0
select num;

İlk sorgudan farklı olarak yukardaki sorguda 100 length lik koleksiyonumuz parçalara ayrılacak ve where şartı her parça için ayrı ayı çalıştırılacak. Sonuçta daha hızlı bir dönüş olacak.

Kullanılması ve Kullanılmaması Gereken Yerler?

1. Büyük Koleksiyonlar ve Kompleks İşlerde

Tüm parallel işlemlerde olduğu gibi PLINQ kullanmanın bir maliyeti vardır. Koleksiyonun önce parçalara ayrılması, kaç farklı thread’de çalıştırılacağı gibi işlemler bir iş yüküdür. İşleme alacağımız koleksiyon yeteri kadar büyük değilse ya da yaptırdığımız işlem kompleks değilse LINQ sorgusu kullanmak daha performanslı olabilir. Yukarıdaki gibi basit bir mod alma işleminde PLINQ yerine LINQ kullanmalıyız. Bu örneği sadece PLINQ uygulanmasının kolayca anlaşılması için verdim.

var numberList= Enumerable.Range(1, 100).ToList();var queryA = (from num in numberList.AsParallel() 
select new
{
num,
hashed = BCrypt.Net.BCrypt.HashPassword(num.ToString())
}).ToList();

Bu koddaki gibi koleksiyondaki her bir sayı için hashleme gibi kompleks bir işlem yapılacaksa PLINQ kullanmak ciddi bir performans sağlar.

1'den 100'e kadar olan listemizdeki sayıları LINQ ve PLINQ sorguları ile hash’leyelim ve çıktı sürelerini görelim.

İlk olarak hash işlemi için BCrypt.Net-Next nuget paketini kuruyorum. Sonrasında ayrı ayrı linq ve plinq sorgularını yazıyorum.

Programı çalıştırdığımızda çıktı şu şekilde olacak.

Bu senaryoda PLINQ sorgusu ile LINQ sorgusu arasında 5 katı kadar bir performans farkı oluşmuştur.

2. Sıralamanın Önemli Olmadığı Durumlarda

PLINQ koleksiyonu parçalar ve sıralama gözetmeksizin işleme alarak sonuçları üretir. Eğer koleksiyonda işlem çıktısının sıralı oluşması isteniyorsa AsOrdered() methodu kullanılabilir. Bu işlemin tabiki ekstra bir maliyeti vardır. PLINQ in en verimli kullanılışı sıralama gözetilmeksizin çalıştırıldığı senaryolardır.

Ayrıca GroupBy ve Join de ekstra iş yükü oluşturmaktadır.

3. PLINQ Sorguları Hafızaya Alınmış Koleksiyonlar Üzerinde Kullanılmalıdır

PLINQ sorguları hafızaya alınan veriler üzerinde uygulanmalıdır. Eğer Entity Framework objeleri üzerinde direk AsParallel() methodu kullanılır ve sonrasında where şartı yazılırsa Entity Framework önce veritabanındaki tüm tabloyu hafızaya alacak sonra where şartını uygulayacaktır. Normal bir linq sorgusunda ise where şartı SQL cümlesine dönüştürülerek direk filtrelenmiş data döndürülmüş olur.

var queryA = (from user in context.Users.AsParallel() 
select new
{
user.UserName,
hashedPasword = BCrypt.Net.BCrypt.HashPassword(user.Password))
}).ToList();

Bu kullanım yanlıştır.

Özetle diğer asenkron yapılarda da olduğu gibi PLINQ bilinçli ve olması gereken yerde kullanıldığında ciddi performans artışları sağlar, aksi taktirde LINQ sorgularından daha yavaş sonuçlar elde edilir.

PLINQ i efektif olarak kullanabilmek için Microsoft dokümanından yapı detaylı olarak incelenip AsParallel, AsOrdered, AsSequential, AsUnOrdered, WithCancellation, WithDegreeOfParallelism, WithMergeOptions, WithExecutionMode, ForAll ve Aggregate methodları ayrı ayrı kullanılmalıdır.

--

--