Language Integrated Query-2

Önceki yazımızda da bahsettiğim gibi elimden geldiği kadar linq konusunda farklı konulara değinmeye çalışacağım demiştim, tabi mutlaka bir linq fonksiyonlarının kullanımını içeren bir yazı yazacağım.

Normalde büyük çoğunluğumuzun tahmin ettiği ve bildiği gibi linq hız konusunda çok daha avantajlı ama bazı durumlar var ki bazı durumlar düşündüğümüz gibi değil.

Aşağıdaki kod bloğunda aynı işi yapan iki grup kod parçacığı olacak, bir tanesi aynı işi for döngüsüyle yapıyor olacak diğeri ise linq metodlarını kullanıyor olacak.


var listSize= 10000000;
var stopwatch= new Stopwatch();
stopwatch.Restart();
var s = Enumerable.Range(1,listSize)
       .Select (n=>n*2) 
       .Select (n=> Math.Sin((2*Math.PI*n)/1000 )) 
       .Select (n=> Math.Pow(n,2))
       .Sum();
stopwatch.Stop();
Console.WriteLine("LINQ {0} items in {1} ms",listSize,stopwatch.ElapsedMilliseconds);
-------------------------------------------------------------------------------------
stopwatch.Restart();
double sum=0;
for(int n=1; n<=listSize; n++)
{
  var a=n*2; 
  var b=Math.Sin((2*Math.PI*a)/1000); 
  var c=Math.Pow(b,2); 
  sum +=c;
}
stopwatch.Stop();
Console.WriteLine("for loop {0} items in {1}",listSize,stopwatch.ElapsedMilliseconds);

Bu kod parçacıklarını linqpad editörü ile derledim.Beklediğimiz üzere linq metodu ile yazılan blok daha hızlı çalışmadı.Klasik yöntem for döngüsü bir miktar da olsa daha performanslı çalıştı.

Böyle olmasının sebebi Enumerable tipli döngülerde lamda expressionın performans sorunu yaşaması, zaten yazılımcılar for,foreach döngülerinden bir bakıma kurtulmak iç içe for döngüleri yazmamak için linq kullanmaktadır. Linq de aslında içeride kendine has bir döngü yapısı olduğu için bir döngü içerisinde lamda expression kullanmak ekstradan zaman kaybettirmektedir.Tabiki döngü içerisinde lamda expression kullanmakta ısrarcı iseniz;

var listSize= 10000000;
var stopwatch= new Stopwatch();
var s = Enumerable.Range(1,listSize).AsParallel()
        .Select (n=>n*2) 
        .Select (n=> Math.Sin((2*Math.PI*n)/1000 ))
        .Select (n=> Math.Pow(n,2))
        .Sum();
stopwatch.Stop();
Console.WriteLine("LINQ {0} items in {1} ms",listSize,stopwatch.ElapsedMilliseconds);

Enumerable döngünüze .AsParallel() extension methodunu ekleyerek, linq kod bloğunuzun kayda değer şekilde hızlı çalışmasını sağlayabilirsiniz.Bunun sebebide arka tarafta daha fazla thread açarak işlemi yapmasıdır.

Func ve Action Tipleri

İki generic yapıda olan Action ve Func delegelerini kullnarak yukarıda yazmış olduğumuz kodu tekrar düzenlemeye çalışacağız. Öncelikle biraz Func ve Action tiplerinden bahsedelim. Aslında bu iki tipte bize kolay yoldan delege tanımlamamızı ve kullanmamızı sağlıyor.

Aşağıdaki örnekte int tipinde bir parametre alan funcString tipi geriye string değerinde bir result döndürmektedir.

    Func<int,string> funcString =(x) =>string.Format("string = {0}", x);

Action tipi int tipinde parametre alıp geriye herhangi bir değer dönmez,dönüş tipi void’dir.

 Action<int> action= (int x) => Console.WriteLine("Write {0}", x);

Şimdi yukarıda yazmış olduğumuz code parçacığını birde func ve action tipleri ile yazalım.

 var stopwatch = new Stopwatch();
 var listSize = 10000000;
 Func<int, double> funcCalculate = (x) =>
 {
 var s = Enumerable.Range(1, x).AsParallel()
 .Select(n => n * 2)
 .Select(n => Math.Sin((2 * Math.PI * n) / 1000))
 .Select(n => Math.Pow(n, 2))
 .Sum();
 return s;
 };
 Action<double> write = (double x) => Console.WriteLine("LINQ {0} items in {1} ms", x, stopwatch.ElapsedMilliseconds);
 write(funcCalculate(listSize));
 stopwatch.Stop();
 Console.ReadKey();

Yukarıda açık olarak yazmış olduğumuz hesaplama işlemini funcCalculate delegesinin içine yazdık. Delege int tipinde bir değer alıp double veri tipinde result dönmektedir. Write actionı ise funcCalculate delegesini de kapsayan bir actiondır. Action ekrana functiondan gelen değeri döndürmektedir. Action tipini sadece bu kapsamda ele almamak daha detaylı bir şekilde kullanmak mümkündür.

Keyifli Çalışmalar.

 

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir