https://buraksenyurt.com/Burak Selim Şenyurt - PLINQ2009-11-11T16:22:50+00:00Matematik Mühendisi Bir Bilgisayar Programcısının NotlarıBurak Selim SenyurtBlogEngine.Net Syndication Generatorhttps://buraksenyurt.com/opml.axdBurak Selim SenyurtMatematik Mühendisi Bir Bilgisayar Programcısının Notlarıtr-TRBurak Selim Şenyurt0.0000000.000000https://buraksenyurt.com/post/PLINQ-ForAllPLINQ - ForAll [Beta 1]2009-05-28T08:43:00+00:00bsenyurt<p>Merhaba Arkadaşlar,</p>
<p>Bildiğiniz gibi bir süredir LINQ sorgularının paralel çalıştırılması ile ilişkili çalışmalarıma ve araştırmalarıma devam etmekteyim. Bu yazımdaki konumuz ise <strong>System.Linq.ParallelEnumerable static </strong>sınıfı içerisinde tanımlanmış olan <strong>ForAll genişletme metodudur(extension methods).</strong></p>
<p><strong>public static void ForAll<TSource>(this ParallelQuery<TSource> source, Action<TSource> action);</strong></p>
<p><strong>ForAll</strong> metodu yukarıdaki prototipinden de görüldüğü gibi <strong>ParallelQuery </strong>referanslarına uygulanabilmektedir. Bununla birlikte metod ikinci parametre olarak, <strong>Action<TSource></strong> tipinden generic bir temsilci almaktadır.</p>
<p><strong>public delegate void Action<in T>(T obj);</strong></p>
<p>Yukarıdaki prototipe göreyse, <strong>Action<T></strong> temsilcisi(delegate), generic tip olarak ForAll metoduna gelen tipi<strong>(TSource)</strong> kullanmaktadır. Bu generic tip tahmin edeceğiniz üzere <strong>ParalleQuery</strong> referansınında kaynak tipidir. Ayrıca temsilci geriye herhangibir <strong>değer döndürmeyen(void)</strong> metodları işaret edebilmektedir.</p>
<p>Sonuç olarak ForAll metodu aslında, <strong>AsParallel</strong> metodunun kullanılması sonucu üretilen referans üzerinden gelen her bir nesne örneği için yapılması istenen işlemleri ele almaktadır. Bu açıdan bakıldığında akla gelen soru şu olacaktır.</p>
<p><em>Paralel sorguların çalışması sonucu üretilen çıktılar üzerinde <strong>foreach</strong> döngüleri yardımıyla da dolaşabiliyorken, <strong>ForAll</strong> metodunu neden kullanırız?</em></p>
<p>Aşağıdaki kod parçasını göz önüne alalım.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Threading;
namespace UsingForAll
{
class Program
{
static void Main(string[] args)
{
List<Product> productList = GetProductList();
var result = from p in productList.AsParallel()//.WithExecutionMode(ParallelExecutionMode.ForceParallelism)
where p.ListPrice>=400 && p.Color=="Black"
select p;
result.ForAll(p=>Console.WriteLine("("+Thread.CurrentThread.ManagedThreadId.ToString()+")\t"+p.Name));
}
static List<Product> GetProductList()
{
List<Product> productList = new List<Product>();
SqlConnection conn = new SqlConnection("data source=Manchester;database=AdventureWorks2008;integrated security=true");
SqlCommand cmd = new SqlCommand("Select ProductId,Name,ListPrice,ProductNumber,Color,SafetyStockLevel From Production.Product", conn);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
productList.Add(new Product
{
ProductId = Convert.ToInt32(reader[0]),
Name = reader[1].ToString(),
ListPrice = Convert.ToDecimal(reader[2]),
ProductNumber = reader[3].ToString(),
Color = reader[4].ToString(),
SafetyStockLevel = Convert.ToInt32(reader[5])
}
);
}
reader.Close();
return productList;
}
}
class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal ListPrice { get; set; }
public string ProductNumber { get; set; }
public string Color { get; set; }
public int SafetyStockLevel { get; set; }
}
}</pre>
<p>Bu kod parçasında odaklanmamız gereken nokta <strong>result</strong> referansı üzerinden <strong>ForAll</strong> metodunun çağırılışıdır. Bu çağrı sırasında <strong>labmda</strong> <strong>operatöründen(=>)</strong> yaralanılmaktadır ve bulunan ürünlerin adları ile o an çalışmakta olan <strong>Thread'</strong> in numarası(<strong>ManagedThreadId</strong>) <strong>Console </strong>ekranına yazdırılmaktadır. Sonuç aşağıdakine benzer olacaktır.</p>
<p><img src="/pics/2009%2f5%2fblg23_1.gif" alt="" /></p>
<p>Her ne kadar <strong>Thread </strong>sayıları eşit olmasada <strong>4 </strong>ve <strong>1 </strong>nolu iki ayrı iş parçasının çalıştırıldığı görülmektedir. Şimdi aynı sorgu sonuçlarını foreach döngüsü yardımıyla elde etmeye çalıştığımızı düşünelim.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">List<Product> productList = GetProductList();
var result = from p in productList.AsParallel()//.WithExecutionMode(ParallelExecutionMode.ForceParallelism)
where p.ListPrice>=400 && p.Color=="Black"
select p;
foreach (Product p in result)
{
Console.WriteLine("(" + Thread.CurrentThread.ManagedThreadId.ToString() + ")\t" + p.Name);
}</pre>
<p>Bu kez uygulama çalıştırıldığında aşağıdaki sonuçları alırız.</p>
<p><img src="/pics/2009%2f5%2fblg23_2.gif" alt="" /></p>
<p>Volaaa!!! <img title="Cool" src="/editors/tiny_mce3/plugins/emotions/img/smiley-cool.gif" alt="Cool" border="0" /> 1 numaralı sadece tek bir thread görünüyor.</p>
<p>Bu nasıl oldu? Acaba <strong>foreach</strong> döngüsü kullanıldığında sorgu <strong>AsParallel</strong> metodu olmasına rağmen paralel çalıştırılmadı mı? Yoksa çalışma zamanı(runtime) sorgunun paralel çalıştırılmaya değer olmadığına mı kanaat getirdi(ki böyle bir meselede var)?</p>
<p>Aslında farklı çalışmanın sebebi şu. LINQ sorguları bilindiği gibi kullanıldıkları yerde çalıştırılırlar(<strong>deferred execution ilkesi</strong>). Bu nedenle sorgunun çalıştırılması foreach döngüsünde ilk eleman elde edilmeye çalışıldığı sırada olur. Lakin sorgu <strong>AsParallel</strong> metodu nedeniyle paralel çalışmasına rağmen, foreach metodu okuma işlemine başlamadan önce tüm yönetimli thread' leri tekrardan tek bir thread içerisinde birleştirir. Yani foreach döngüsünün kendisi paralel çalışma özelliğne sahip değildir. Bu nedenle paralel çalıştırılan sorgu sonuçlarını, o an üzerinde çalıştığı thread' de birleştirmeden ilerleyemez. <strong>ForAll</strong> metodu ise tam aksine çalışmakta olup, okuma işlemlerininde paralel yürütülmesini sağlamaktadır. Aslında durumu basit iki resim ile canlandırmaya çalışalım. Aşağıdaki şekilde foreach çalışması sırasındaki işleyiş sembolize edilmektedir.</p>
<p><img src="/pics/2009%2f5%2fblg23_4.gif" alt="" /></p>
<p>Buna göre sorgu paralel olarak çalışan görevlere ayrılmakta ve herbir görev içerisinde where gibi koşullar ele alınmaktadır. Ancak tüm PLINQ ifadesi tamamlandığında sonuçlar tek bir Task altında birleştirilmektedir. (Kahverengi çerçeveli kutucuklar bulunan nesne örnekleri üzerinden yapılan işlemleri sembolize etmektedir. Örneğin Console.WriteLine gibi) Sonrasında ise herbir öğe için foreach döngüsü içerisinde yazılan kodlar işletilmektedir.</p>
<p>Aşağıdaki şekilde ise ForAll kullanımı sırasındaki senaryo ifade edilmeye çalışılmaktadır.</p>
<p><img src="/pics/2009%2f5%2fblg23_3.gif" alt="" /></p>
<p>Yine PLINQ ifadesinin çalışması sırasında n adet Task paralel olarak başlatılır. Ancak foreach' ten farklı olarak her task' in içerisinde hem Where gibi koşulların kontrolü ele alınmakta hemde örneğimizde ki her bir sonuç için ayrı ayrı işlemler(Console.WriteLine gibi) gerçekleştirilmektedir. Yani task' ler paralel olarak işledikten sonra tek bir Task altında birleştirilmezler. Sanıyorum şekil yardımıyla sizde benim gibi, gerçekleşen iki farklı işleyişi daha net canlandırabildiniz. <em>(Tabi işlemcinin içerisine girip olan biteni canlı canlı görmemiz mümkün değil. Ama kim bilir, belki gelecek nesil sistemlerde çalışma zamanını, tıpkı bir doktorun sanal bir hastanın organları içerisinde ilerleyişi gibi, bilgisayar donanımı üzerindem gözlemleyebiliriz. <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" />)</em></p>
<p><em>Herşey güzel ama, hangisini ne zaman kullanmak gerekir öyleyse?</em></p>
<p>Aslında foreach döngüsünü daha çok sorgu sonuçlarının <strong>sırasını(order)</strong> korumak istediğimiz durumlarda değerlendirebiliriz. Bununla birlikte, sonuç listesi üzerinde ardışıl olarak işlemler yapmak istiyorsakta tercih edebiliriz.</p>
<p>Böylece geldik kısa bir yazımızın daha sonuna. Bir sonraki yazımızda görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://buraksenyurt.com/pics/2009%2f5%2fUsingForAll.rar">UsingForAll.rar (22,17 kb)</a></p>2009-05-28T08:43:00+00:00plinqlinqbsenyurtBildiğiniz gibi bir süredir LINQ sorgularının paralel çalıştırılması ile ilişkili çalışmalarıma ve araştırmalarıma devam etmekteyim. Bu yazımdaki konumuz ise System.Linq.ParallelEnumerable static sınıfı içerisinde tanımlanmış olan ForAll genişletme metodudur(extension methods).https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=ed839f1d-5a9b-4da2-a6f8-002e3afe68b10https://buraksenyurt.com/trackback.axd?id=ed839f1d-5a9b-4da2-a6f8-002e3afe68b1https://buraksenyurt.com/post/PLINQ-ForAll#commenthttps://buraksenyurt.com/syndication.axd?post=ed839f1d-5a9b-4da2-a6f8-002e3afe68b1https://buraksenyurt.com/post/Paralel-Sorgularda-Istisna-Yonetimi(Exception-Handling)Paralel Sorgularda İstisna Yönetimi(Exception Handling) [Beta 1]2009-05-26T05:30:00+00:00bsenyurt<p>Merhaba Arkadaşlar,</p>
<p><strong>Yönetimli kod(Managed Code)</strong> tarafında istisna yönetimi oldukça önemli konulardan birisidir. Uygulamaların veya kod süreçlerinin istem dışı sonlanmasının önüne geçilmek istendiği durumlarda, basit <strong>try...catch...finally </strong>bloklarından yararlanabilir yada <strong>Enterprise Library </strong>gibi kütüphanelerin sunduğu bloklardan faydalanarak istisna yönetimini üst seviyede sağlayabiliriz.</p>
<p>Bu yazımda çok geniş kapsamda düşünmeyip, <strong>PLINQ(Parallel Language INtegrated Query)</strong> ifadelerinde oluşabilecek istisnai durumların nasıl ele alınması gerektiği üzerinde durmaya çalışacağız. Olaya hızlı bir giriş yapıp aşağıdaki örnek kod parçasına sahip olduğumuzu düşünelim.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
namespace SequentialPLINQ
{
class Program
{
static void Main(string[] args)
{
List<Product> productList = GetProductList();
productList[497].SafetyStockLevel = 0;
productList[503].SafetyStockLevel = 0;
var result1 = from product in productList.AsParallel()
orderby product.ProductId
where product.ListPrice>=500
select new
{
product.ProductId,
product.Name,
product.ListPrice,
product.Color,
SellPrice=FindSellPrice(product.ListPrice,product.SafetyStockLevel) // İlk durum
};
try
{
foreach (var r in result1)
{
Console.WriteLine(r.ProductId + " " + r.Name + " (" + r.SellPrice.ToString("C2") + ")");
}
}
catch (AggregateException excp) // Hata oluştuğunda PLINQ içerisinde başlatılan tüm alt işlemler(Threads) iptal edilir
{
// PLINQ ifadeleri çalıştırıldığı sırada oluşan istisnalar AggreateException nesne örneği içerisindeki InnerExceptions özelliğinin refere ettiği koleksiyonda toplanırlar.
foreach (Exception error in excp.InnerExceptions)
{
Console.WriteLine(error.Message);
}
}
}
static decimal FindSellPrice(decimal listPrice,int stockLevel)
{
decimal result=-1;
if (DateTime.Now.Day >= 25
&& DateTime.Now.Day <= 28)
result=listPrice - (listPrice * (1 / stockLevel)); // SafetyStockLevel' ın 0 gelmesi halinde exception oluşacak olan yer.
else
result= listPrice * 1.18M;
return result;
}
static List<Product> GetProductList()
{
List<Product> productList = new List<Product>();
SqlConnection conn = new SqlConnection("data source=Manchester;database=AdventureWorks2008;integrated security=true");
SqlCommand cmd = new SqlCommand("Select ProductId,Name,ListPrice,ProductNumber,Color,SafetyStockLevel From Production.Product", conn);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
productList.Add(new Product
{
ProductId = Convert.ToInt32(reader[0]),
Name = reader[1].ToString(),
ListPrice = Convert.ToDecimal(reader[2]),
ProductNumber = reader[3].ToString(),
Color = reader[4].ToString(),
SafetyStockLevel = Convert.ToInt32(reader[5])
}
);
}
reader.Close();
return productList;
}
}
class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal ListPrice { get; set; }
public string ProductNumber { get; set; }
public string Color { get; set; }
public int SafetyStockLevel { get; set; }
}
}</pre>
<p><strong>Visual Studio 2010 Professional Beta 1 </strong>ile geliştirilen bu kod parçasında, <strong>Product</strong> isimli bir sınıftan yararlanılmaktadır. Product tipine ait veriler, SQL sunucusu üzerindeki Product tablosundan alındıktan sonra, generic <strong>List<Product></strong> koleksiyonu içerisinde tutulmakta ve sonrasında ise paralel sorgulamaya tabi tutulmaktadır. Burada ayrıca dikkat edilmesi gereken bir noktada, sorgulama sırasında <strong>FindSellPrice</strong> isimli metodun çağırılması ve parametre olarak, sorgunun t anındaki <strong>Product</strong> nesnesine ait <strong>ListPrice</strong> ile <strong>StockLevel</strong> değerlerinin gönderilmesidir. Dikkat edileceği üzere <strong>FindSellPrice</strong> metodu içerisinde güne göre ürünlerde indirim uygulanmasını hedef alan bir formül yer almaktadır. Formülü tamamen kafadan uydurduğumu ifirat etmek isterim. Zaten sizde bunu anlamışsınızdır. <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> Asıl varmak istediğim nokta, StockLevel değerlerinin 497 ve 503 nolu ürünler için bilinçli olarak sıfıra set edilmiş olmasıdır. Bu nedenle bölme işlemi sırasında bir istisna oluşması kaçınılmazdır.</p>
<p><em>(Yani kendi kendimize kaşınıp kod içerisine bir bubi tuzağı koymuş durumdayız. <img src="/pics/2009%2f5%2fblg22_3.jpg" alt="" width="31" height="36" />) </em></p>
<p>Önemli olan nokta, paralel sorgu motorunun bu tip bir durum ile karşılaştığında ne yapacağıdır. Nitekim söz konusu sorgulama tekniğine göre, operasyon bir kaç parça <strong>Thread'</strong> e bölünmete ve bu nedenle oluşacak bir istisnada(veya istisnalarda) çalışan iş parçalarına ne olacağı sorusu akla gelmektedir. İşte kodun yukarıdaki halinin çalışması sonrası ekran görüntümüz.</p>
<p><img src="/pics/2009%2f5%2fblg22_1.gif" alt="" /></p>
<p>Görüldüğü gibi hiç bir Product bilgisi ekrana çıktı olarak gelmemiştir. Bu son derece doğaldır. Nitekim paralel sorgulama motoru herhangibir istisna ile karşılaştığında, çalışmakta olan tüm <strong>Thread'</strong> lerin iptal edilmesini sağlamaktadır. Diğer yandan istisna nesnesinin tipine dikkat edilmelidir. <strong>PLINQ</strong> ifadeleri içerisinde meydana gelebilecek istisnalar, <strong>AggregateException</strong> istisna sınıfı tarafından sarmalanmaktadır. Birden fazla istisna olabileceğinden, AggregateException sınıfı <strong>InnerExceptions</strong> isimli birde özelliğe sahiptir. Dolayısıyla <strong>catch</strong> bloğu içerisinde, sıfıra bölem hatasının yakalanması için, <strong>InnerExceptions</strong> koleksiyonunda dolaşılması gerekemtekdir. <em>(InnerExceptions özelliği ReadOnlyCollection<Exception> tipinden bir koleksiyon döndürmektedir.)</em></p>
<p>Peki ya, istisna olan parçaların atlanması(bu örneğe göre) istenirse. Bir başka deyişle istisna almayan parçaların yinede paralel sorgulama sonucu ele alınması istenirse ne yapabiliriz?</p>
<p>Bu sorunun cevabı son derece basittir aslında. Exception yönetimi, <strong>FindSellPrice</strong> isimli metod içerisinde gerçekleştirilir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">static decimal FindSellPrice(decimal listPrice,int stockLevel)
{
decimal result=-1;
try
{
if (DateTime.Now.Day >= 25 && DateTime.Now.Day <= 28)
result=listPrice - (listPrice * (1 / stockLevel)); // SafetyStockLevel' ın 0 gelmesi halinde exception oluşacak olan yer.
else
result= listPrice * 1.18M;
}
catch(DivideByZeroException excp)
{
Console.WriteLine("\tStok miktarı 0 olduğundan satış fiyatı hesaplanamadı");
}
return result;
}</pre>
<p>Bu durumda uygulama başarılı bir şekilde çalışacak ve aşağıdaki ekran görüntüsüne benzer sonuçlar alınacaktır.</p>
<p><img src="/pics/2009%2f5%2fblg22_2.gif" alt="" /></p>
<p>Görüldüğü gibi istisnaya neden olan ürünler kontrollü bir şekilde elenmiş ve sorgunun paralel olarak yürütülmesine devam edilebilmiştir. Böylece geldik bir yazımızın daha sonuna. Bu yazımızda PLINQ sorgularında, istisna yönetiminde nelere dikkat etmemiz gerektiğine değinmeye çalıştık. Tekrardan görüşünceye dek hepinize mutlu günler dilerim. </p>
<p><a href="https://buraksenyurt.com/pics/2009%2f5%2fExceptionHandling.rar">ExceptionHandling.rar (27,33 kb)</a></p>2009-05-26T05:30:00+00:00plinqlinqbsenyurtYönetimli kod(Managed Code) tarafında istisna yönetimi oldukça önemli konulardan birisidir. Uygulamaların veya kod süreçlerinin istem dışı sonlanmasının önüne geçilmek istendiği durumlarda, basit try...catch...finally bloklarından yararlanabilir yada Enterprise Library gibi kütüphanelerin sunduğu bloklardan faydalanarak istisna yönetimini üst seviyede sağlayabiliriz.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=80463ba2-920e-40ca-88ee-f96ccec184980https://buraksenyurt.com/trackback.axd?id=80463ba2-920e-40ca-88ee-f96ccec18498https://buraksenyurt.com/post/Paralel-Sorgularda-Istisna-Yonetimi(Exception-Handling)#commenthttps://buraksenyurt.com/syndication.axd?post=80463ba2-920e-40ca-88ee-f96ccec18498https://buraksenyurt.com/post/PLINQ-Paralellik-Altc4b1nda-Ardc4b1sc4b1k(Sequential)-Calc4b1smakPLINQ - Paralellik Altında Ardışık(Sequential) Çalışmak [Beta 1]2009-05-25T11:34:00+00:00bsenyurt<p>Merhaba Arkadaşlar,</p>
<p>Bir önceki blog yazımızda PLINQ ifadelerinde sıralama konusuna değinmeye çalışmıştık. Bu yazımızda ise, paralel olarak çalıştırılan LINQ sorguları içerisinde, <strong>ardışık(Sequential)</strong> olarak nasıl işlem yapılabileceğini incelemeye çalışacağız.</p>
<p>PLINQ ifadeleri, sorgu içerisindeki işlemleri paralel çalışan görevlere ayırmakta son derece başarılıdır. Ancak öyle senaryolar olabilirki, sorgunun belirli bir noktasından(noktalarından) sonra ardışık olarak işlemlerin devam etmesi istenebilir<em>.(Hatta sonra tekrardan paralel olarak devam edilmeside sağlanabilir)</em> Tabi bu şekilde anlatmaya çalışınca inanın benim kafamda karışıyor. <img title="Undecided" src="/editors/tiny_mce3/plugins/emotions/img/smiley-undecided.gif" alt="Undecided" border="0" /> Gelin olayı basit bir örnek ile ele almaya çalışalım. İşte <strong>Visual Studio 2010 Professional Beta 1 </strong>üzerinde geliştirdiğim Console uygulamasına ait kodlar.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
namespace SequentialPLINQ
{
class Program
{
static void Main(string[] args)
{
List<Product> productList = GetProductList();
int tid= 0;
var result1 = from product in productList.AsParallel()
where product.Color.StartsWith("B")
orderby product.ProductId
select new
{
Id = tid++,
product.ProductId,
product.Name,
product.ListPrice,
product.Color
};
foreach (var r in result1)
{
Console.WriteLine(r.Id+" \t"+r.ProductId+" "+r.Name+" "+r.Color);
}
}
static List<Product> GetProductList()
{
List<Product> productList = new List<Product>();
SqlConnection conn = new SqlConnection("data source=Manchester;database=AdventureWorks2008;integrated security=true");
SqlCommand cmd = new SqlCommand("Select ProductId,Name,ListPrice,ProductNumber,Color,SafetyStockLevel From Production.Product", conn);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
productList.Add(new Product
{
ProductId=Convert.ToInt32(reader[0]),
Name=reader[1].ToString(),
ListPrice=Convert.ToDecimal(reader[2]),
ProductNumber=reader[3].ToString(),
Color=reader[4].ToString(),
SafetyStockLevel=Convert.ToInt32(reader[5])
}
);
}
reader.Close();
return productList;
}
}
class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal ListPrice { get; set; }
public string ProductNumber{ get; set; }
public string Color { get; set; }
public int SafetyStockLevel { get; set; }
}
}</pre>
<p>Örnekte SQL Server 2008 üzerinde kurulu olan, <strong>AdventureWorks2008</strong> veritabanındaki <strong>Production</strong> şemasında yer alan <strong>Product </strong>tablosuna ait veriler kullanılmaktadır. Product tablosunun kod içerisindeki temsili için, Product isimli bir sınıf tasarlanmıştır. Sınıfa ait nesne örneklerinden oluşan generic <strong>List<Product></strong> koleksiyonunun doldurulması için <strong>GetProductList </strong>metodundan yararlanılmaktadır. Söz konusu generic liste <strong>PLINQ</strong> ifadesi yardımıylada sorgulanmaktadır. Buraya kadarki kısımda zaten ilginç bir şey yok. Dikkat edeceğimiz nokta, <strong>isimsiz tip(Anonymous Type)</strong> içerisinde <strong>tid</strong> isimli sayacın arttırılmasıdır. <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> Öyleki uygulamayı çalıştırdığımızda aşağıdaki sonuçları elde ederiz.</p>
<p><img src="/pics/2009%2f5%2fblg21_1.gif" alt="" /></p>
<p>Burada dikkat edilmesi gereken nokta <strong>tid</strong> değerlerinin ardışık mantığa göre değil, paralel çalışmanın bir sonucu olarak farklı sıralarda üretilmesidir. Bu nedenle 1, 3, 5, 8, 74... gibi bir dizi oluşmuştur. Bu dizi kodun her çalıştırılmasında farklı şekillerde üretilebilir. Örneği ikinci kez çalıştırdığımda bu kez aşağıdaki sonuçları aldım.</p>
<p><img src="/pics/2009%2f5%2fblg21_2.gif" alt="" /></p>
<p>Görüldüğü üzere <strong>tid</strong> değerlerinin arttırımının, çıktıya yansıyışı farklı olmaktadır. Hatta <strong>MSDN</strong> kaynaklarında, arttırımı yapılan değerlerin tekrar etmesininde mümkün olabileceği berlitilmektedir. İşte yazmış olduğum bu anlamsız örnekteki gibi <em>(örneğin arttırım işlemlerinin ardışık bir şekilde gerçekleştirilmesinin gerektiği vb...), </em>paralel olarak çalışan LINQ sorguları içerisinde, ardışık çalışması gereken bölümler var ise, <strong>AsSequential</strong> <strong>genişletme metodunun(Extension Method)</strong> kullanılması gerekmektedir. Buna göre yukarıdaki örnekte yer alan LINQ sorgusunu,</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">var result1 = productList
.AsParallel()
.Where(p => p.Color.StartsWith("B"))
.OrderBy(p => p.Name)
.AsSequential()
.Select(
p => new
{
Id = tid++,
p.ProductId,
p.Name,
p.ListPrice,
p.Color
});</pre>
<p>şeklinde değiştirir ve örneği tekrar çalıştırırsak aşağıdaki sonuçları elde ederiz.</p>
<p><img src="/pics/2009%2f5%2fblg21_3.gif" alt="" /></p>
<p>Görüldüğü gibi <strong>tid</strong> arttırımı düzenli bir şekilde çıktıya yansıtılmıştır. (<em>Yinede dikkatlice baktığınızda Name özelliğine göre yapılan sıralamalarda, her iki LINQ sorgusu arasında küçük farklar olabileceğini görebilirsiniz)</em></p>
<p>Sonuç olarak paralel olarak çalıştırılan LINQ sorguları içerisinde, ardışık yürütülmesi gereken operasyonlar var ise bu durumda <strong>AsSequential</strong> genişletme metodnun kullanılması gerekmektedir. Diğer taraftan elbetteki bu kullanım, söz konusu paralel çalışmanın hızını düşürecek bir etkiye neden olacaktır. Bu da gözden kaçırılmaması gereken diğer bir noktadır.</p>
<p>Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://buraksenyurt.com/pics/2009%2f5%2fSequentialPLINQ.rar">SequentialPLINQ.rar (25,80 kb)</a></p>2009-05-25T11:34:00+00:00plinqlinqbsenyurtBir önceki blog yazımızda PLINQ ifadelerinde sıralama konusuna değinmeye çalışmıştık. Bu yazımızda ise, paralel olarak çalıştırılan LINQ sorguları içerisinde, ardışık(Sequential) olarak nasıl işlem yapılabileceğini incelemeye çalışacağız.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=aa6a1e74-86e5-4e9c-94d9-ce4b403373550https://buraksenyurt.com/trackback.axd?id=aa6a1e74-86e5-4e9c-94d9-ce4b40337355https://buraksenyurt.com/post/PLINQ-Paralellik-Altc4b1nda-Ardc4b1sc4b1k(Sequential)-Calc4b1smak#commenthttps://buraksenyurt.com/syndication.axd?post=aa6a1e74-86e5-4e9c-94d9-ce4b40337355https://buraksenyurt.com/post/PLINQ-Siralamayi(Ordering)-KorumakPLINQ - Sıralamayı(Ordering) Korumak [Beta 1]2009-05-23T20:30:00+00:00bsenyurt<p>Merhaba Arkadaşlar,</p>
<p>Hatırlayacağınız gibi, <strong>PLINQ(Parallel LINQ) </strong>ile ilişkili ilk <a title="PLINQ - Hello World" href="https://buraksenyurt.com/post/PLINQ-(Parallel-LINQ)-Hello-World" target="_blank">yazımda</a>, LINQ sorgularının eş zamanlı olarak nasıl çalıştırılabileceğini incelemeye çalışmıştık. Hello World örneğimizde ağırlıklı olarak aşağıdaki sorgu üzerinde durmuştuk.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">var result2 = from p in products.AsParallel()
where p.ListPrice >= 10 && p.InStock==true
orderby p.Name descending
select p;</pre>
<p>Bu sorguda yer alan orderby kelimesi aslında çok büyük bir öneme sahiptir. Gelin ne demek istediğimi size anlatmaya çalışayım. Yine <strong>Visual Studio 2010 Professional Beta 1 </strong>ortamında geliştirilen aşağıdaki kod parçasına sahip bir Console uygulamamız olduğunu göz önüne alacağız.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Collections.Generic;
using System.Linq;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
List<Product> products = FillProducts();
Console.WriteLine("Liste dolduruldu. İşlemlere devam etmek için tıklayın");
Console.ReadLine();
Console.WriteLine("Listenin ilk hali");
foreach (Product prd in products)
{
if(prd.InStock==true)
Console.WriteLine(prd.Name);
}
var result = from p in products.AsParallel()
where p.InStock == true
select p;
Console.WriteLine("AsParalell sonrası listenin hali");
foreach (Product prd in result)
{
Console.WriteLine(prd.Name);
}
}
static List<Product> FillProducts()
{
List<Product> products = new List<Product>();
for (long i = 1; i < 21; i++)
{
Product prd = new Product
{
Id = i
,Name = "Product" + i.ToString()
,ListPrice = i * 0.1M
,InStock = i % 2 == 0 ? true : false
};
products.Add(prd);
}
return products;
}
}
class Product
{
public long Id { get; set; }
public string Name { get; set; }
public decimal ListPrice { get; set; }
public bool InStock { get; set; }
}
}</pre>
<p>Bu seferki örneğimizde temel amacımız hız veya işlemlerin daha kısa sürede tamamlanması değildir. products isimli generic List koleksiyonu doldurulduktan sonra bir foreach döngüsü yardımıyla dolaşılmakta ve stokta olanlar(InStock==true) ekrana yazdırılmaktadır. Sonrasında ise <strong>PLINQ</strong> sorgumuz gelmekte ve aynı sonuçları paralel çalışan task' ler üzerinde elde etmemizi sağlamaktadır. Hemen küçük bir dip not belirtelim; LINQ sorguları aslında kullanıldıkları anda çalıştırılmaktadır<strong>(Deferred Execution).</strong> Yani çalışma zamanında ikinci foreach döngüsüne gelindiğinde, söz konusu PLINQ sorgusu yürütülmekte ve dolayısıyla paralel görevler devreye girmektedir. Peki herşey güzel hoş... Hoş ama niye bunun üzerinde duruyoruz? Aslında çalışma zamanındaki ekran görüntüsü herşeyi biraz olsun açıklıyor.</p>
<p><img src="/pics/2009%2f5%2fblg20_1.gif" alt="" /></p>
<p>Dikkat edileceği üzere, listenin ilk halinde stokta olan ürünler, koleksiyonda yer aldıkları sıraya göre ekrana getirilmektedir. Ancak <strong>AsParallel </strong>genişletme metodunun kullanılması sonrasında elde edilen listedeki ürünler sıralı bir şekilde gelmemektedir. Bu çok doğal olarak paralel çalışmanın bir sonucudur. Ancak bazı hallerde <strong>AsParallel</strong> kullanımı sonrasında, kaynak listenin sıralı olarak elde edilmesi istenebilir. Bu durumda <strong>orderby</strong> kullanımı sorunu çözecektir. Söz gelimi yukarıdaki örnekte yer alan LINQ ifadesinde orderby aşağıdaki gibi kullanılabilir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">var result = from p in products.AsParallel()
where p.InStock == true
orderby p.Name
select p;</pre>
<p>Bu durumda örneğin çalışması sonucu aşağıdaki çıktı elde edilir.</p>
<p><img src="/pics/2009%2f5%2fblg20_2.gif" alt="" /></p>
<p>Ancak PLINQ tipinden sorgunun çalıştırılması sırasında orjinal nesne sırasının korunması da istenebilir ki bu orderby kullanımından daha farklı anlamdadır. <em>(orderby kullanımında listenin, koleksiyondaki orjinal sırası yerine, sıralama kriteri belirtilir.)</em> İşte bu noktada devreye <strong>ParallelEnumerable</strong> static sınıfı içerisinde tanımlanmış olan <strong>AsOrdered </strong>isimli <strong>genişletme metodu(Extension Method)</strong> girer. Yani sorguyu aşağıdaki hale getirirsek, liste elemanlarının koleksiyon içerisindeki orjinal sırasını koruyarak sonuç elde edilmesi sağlanabilir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">var result = from p in products.AsParallel().AsOrdered()
where p.InStock == true
select p;</pre>
<p>Ve sonuç...</p>
<p><img src="/pics/2009%2f5%2fblg20_3.gif" alt="" /></p>
<p>Tabi burada önemli bir nokta daha vardır. AsOrdered çok doğal olarak PLINQ sorgunun çalışma zamanında <span style="text-decoration: underline;">yavaş işlemesine</span> neden olacaktır. Çünkü, sorgu sonucu elde edilen liste eşitliğin sol tarafına aktarılmadan önce, AsOrdered nedeni ile orjinal sıra konumlarına yerleştirilir. Bu ek işlem, sonucun elde edilmesini yavaşlatacaktır. Bu nedenle <strong>MSND</strong> kaynaklarında, <strong>AsOrdered</strong> genişletme metodunun gerekmedikçe kullanılmaması öğütlenmektedir. Hatta, <strong>orderby</strong> kullanımının tercih edilmesi önerilmektedir. Yazımızın başında belirttiğimiz Orderby kullanımının neden önemli olduğunu sanırım anlamış bulunuyoruz. Tabiki zorunlu hallerde <strong>AsOrdered </strong>kullanılmasıda gerekebilir.</p>
<p>Bu yazımda sizlere önemsiz gibi görünen fakat dikkat edilmesi gereken bir konuyu aktarmaya çalıştım. Bir sonraki yazımızda görüşünceye dek mutlu günler dilerim.</p>
<p><a href="https://buraksenyurt.com/pics/2009%2f5%2fOrdering.rar">Ordering.rar (22,74 kb)</a></p>2009-05-23T20:30:00+00:00plinqlinqbsenyurtHatırlayacağınız gibi, PLINQ(Parallel LINQ) ile ilişkili ilk yazımda, LINQ sorgularının eş zamanlı olarak nasıl çalıştırılabileceğini incelemeye çalışmıştık. Hello World örneğimizde ağırlıklı olarak aşağıdaki sorgu üzerinde durmuştuk.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=fe1ff45d-ded4-4c02-8b1b-04ba46a9ae6e0https://buraksenyurt.com/trackback.axd?id=fe1ff45d-ded4-4c02-8b1b-04ba46a9ae6ehttps://buraksenyurt.com/post/PLINQ-Siralamayi(Ordering)-Korumak#commenthttps://buraksenyurt.com/syndication.axd?post=fe1ff45d-ded4-4c02-8b1b-04ba46a9ae6ehttps://buraksenyurt.com/post/PLINQ-(Parallel-LINQ)-Hello-WorldPLINQ (Parallel LINQ) - Hello World [Beta 1]2009-05-21T19:11:00+00:00bsenyurt<p>Merhaba Arkadaşlar,</p>
<p>Bildiğiniz gibi son yazımı deniz kenarında bir kafede tatildeyken yazmıştım <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> Ama tatil bitti malesef ve tekrardan Morpheus' un sözleri kulaklarımda çınladı <strong>"Wellcome to the real world".</strong> <img title="Cry" src="/editors/tiny_mce3/plugins/emotions/img/smiley-cry.gif" alt="Cry" border="0" /> Yinede 1 haftalığınada olsa tatil yapabildiğime şükrediyorum. Gerçek dünyaya döndükten sonra tabiki bir süre adaptasyon sorunları ile karşılaşıyor insan doğal olaraktan. Bu adaptasyon sorunları içerisinde boğuşurken, neleri araştırabilirim diye düşünürken buluverdim kendimi.</p>
<p>Herşeyden önce <strong>.Net Framework 4.0</strong> ve <strong><a title="Visual Studio 2010 Beta 1" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=255fc5f1-15af-4fe7-be4d-263a2621144b&displaylang=en" target="_blank">Visual Studio 2010 Beta 1</a></strong> sürümlerinin yayınlandığını hepimiz biliyoruz. Dolayısıyla odaklanılacak konu zaten ap açık ortadaydı. .Net Framework 4.0 içerisinde entegre olarak gelen bir yenilik hemen ilgi odağım oldu. <strong>PLINQ(Parallel Language INtegrated Query)</strong>. Aslında PLINQ yeni çıkmış bir eklenti değil. Zaten uzun süredir <strong>.Net Framework 3.5 </strong>ve <strong>Visual Studio 2008 </strong>üzerinde CTP sürümü ile testlerimizi yapabiliyorduk. Ne varki, .Net Framework 4.0 göz önüne alındığında PLINQ ile ilişkili tiplerin <strong>System.Core.dll</strong> assembly' ının <strong>4.0</strong> versiyonu içerisine doğrudan ilave edildiğini görüyoruz. Aşağıdaki Visual Studio 2010 Object Browser' dan alınan görüntüde bu durum açık bir şekilde gözlemlenebiliyor.</p>
<p><a href="https://buraksenyurt.com/pics/2009%2f5%2fblg18_1big.gif" target="_blank"><img src="/pics/2009%2f5%2fblg18_1mini.gif" alt="" /></a></p>
<p>Tabiki öncelikli olarak <strong>PLINQ</strong> kavramından biraz bahsetmemizde yarar var. PLINQ aslında, <strong>Microsfot Research </strong>ve <strong>CLR(Common Language Runtime) </strong>takımları tarafından ortaklaşa geliştirilen <strong>Parallel Extensions </strong>isimli genişletmelerin sadece bir paçasıdır. Diğer parça ise <strong>TBL(Task Parallel Library) </strong>dir.(Bunu ilerleyen yazılarımda ele almaya çalışacağım) Her iki yapının kullanım amacı, <strong>Yönetimli Kod(Managed Code)</strong> tarafındaki eş zamanlı işleyişlerin kolay bir şekilde sağlanmasıdır. Söz konusu yapı PLINQ olunca haliyle, LINQ sorgularının kendi içerisine parçalanarak farklı <strong>thread'</strong> lerde çalışması ve bu parçaların paralel yürüyerek sonuçların elde edilmesi akla gelmektedir. Gerçektende PLINQ yapısının temel amacı bu şekilde özetlenebilir. Hatta PLINQ için <strong>Eş Zamanlı Sorgu Yürütme Motorudur(Concurrency Query Execution Engine)</strong> diyebiliriz. PLINQ temel olarak <strong>LINQ to XML </strong>ve <strong>LINQ to Objects </strong>gibi uygulama alanları üzerinde etkin bir şekilde kullanılabilmektedir.</p>
<blockquote>
<p>Unutulmaması gereken noktalardan biriside, PLINQ ifadelerinin aslında çift çekirdek ve üstü işlemcilerin yada birden fazla işlemcinin olduğu sistemlerde anlamlı olmasıdır. Nitekim, PLINQ motoru, çalışmakta olan sorgu sürecini, makinenin sahip olduğu çekirdek sayısına göre parçalara ayırır ve yürütür. Bu özellikle büyük çaplı projeler göz önüne alındığında, şirketin sahip olduğu kaç bilgisayar var ise hepsini en azından çift çekirdekli olacak şekilde yenilemek gibi bir maliyet anlamına da <span style="text-decoration: underline;">gelmemelidir</span>.</p>
<p>Nitekim bazı istemci-sunucu mimarilerinde, sunucu tarafında çalışmakta olan pek çok LINQ sorgusu, PLINQ motoru kullanılaraktan daha efektif hale getirilebilir. Bir başka deyişle, istemciler birden fazla çekirdekli işlemcilere sahip olmasalarda, mümkün mertebe LINQ ifadelerini içeren iş mantıklarının, sunucu tarafında olduğu senaryolarda PLINQ büyük avantajlar sağlayabilir(Çok kısa bir süre önce çalışmakta olduğum bir projede yer alan test makinesinin, 8 işlemcili olduğunu hatırlıyorum <img title="Laughing" src="/editors/tiny_mce3/plugins/emotions/img/smiley-laughing.gif" alt="Laughing" border="0" /> )</p>
</blockquote>
<p>Tabi burada var olan nesneler üzerindeki LINQ sorgularının paralel olarak çalıştırılması için, <strong>Select, Where </strong>gibi <strong>genişletme metodlarının(Extension Methods) </strong>çalışma sırasında işi farklı parçalara bölebilecek versiyonlarının olması gerektiği düşünülebilir. İşte bu noktada devreye, <strong>System.Core assembly' </strong>ının <strong>4.0 </strong>versiyonu içerisinde yer alan ve <strong>System.Linq </strong>isim alanında bulunan <strong>ParallelEnumerable </strong>adlı <strong>static </strong>sınıf girmektedir.</p>
<p><img src="/pics/2009%2f5%2fblg18_2.gif" alt="" /></p>
<p>Bu sınıftaki en önemli genişletme <strong>AsParallel</strong> isimli fonksiyondur. Bu metodun görevi, <strong>IEnumerable</strong> türevli bir koleksiyonun paralel olarak sorgulanabilir hale getirilmesi veya hazırlanmasıdır. Öyleki, metod geriye <strong>ParallelQuery </strong>isimli sınıfa ait bir nesne örneği döndürmektedir. <strong>ParallelQuery </strong>sınıfı <strong>IEnumerable </strong>arayüzünü uygulamaktadır ama herşeyden önemlisi paralel sorgulanabilme için gerekli ön hazırlıkları içeren operasyonlarada sahiptir.</p>
<p>Bu teknik detaylar eminimki bir Hello World yazısında sizede sıkıcı gelmiştir. Hiç vakit kaybetmeden basit bir örnek ile ilerlemekte yarar olduğunu düşünmekteyim. Aşağıdaki kod parçası <strong>Visual Studio 2010 Beta 1 </strong>sürümünde yazılmış basit bir <strong>Console </strong>uygulamasına aittir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
List<Product> products = FillProducts();
Console.WriteLine("Liste dolduruldu. İşlemlere devam etmek için tıklayın");
Console.ReadLine();
Stopwatch watch = Stopwatch.StartNew();
var result1 = from p in products
where p.ListPrice >= 10 && p.InStock == true
orderby p.Name descending
select p;
Console.WriteLine("Toplam {0} adet ürün bulundu",result1.ToList().Count.ToString());
Console.WriteLine("Toplam süre {0}",watch.ElapsedMilliseconds.ToString());
Console.WriteLine("Parallel Olduğunda");
Stopwatch watch2 = Stopwatch.StartNew();
var result2 = from p in products.AsParallel()
where p.ListPrice >= 10 && p.InStock==true
orderby p.Name descending
select p;
Console.WriteLine("Toplam {0} adet ürün bulundu", result2.ToList().Count.ToString());
Console.WriteLine("Toplam süre {0}", watch2.ElapsedMilliseconds.ToString());
}
static List<Product> FillProducts()
{
List<Product> products = new List<Product>();
for (long i = 1; i < 1750000; i++)
{
Product prd = new Product {
Id = i
, Name = "Product" + i.ToString()
, ListPrice = i * 0.1M
, InStock=i%2==0?true:false
};
products.Add(prd);
}
return products;
}
}
class Product
{
public long Id { get; set; }
public string Name { get; set; }
public decimal ListPrice { get; set; }
public bool InStock { get; set; }
}
}</pre>
<p>Uygulama içerisinde <strong>Products</strong> isimli bir sınıf ve bu tipe ait nesne örneklerinden oluşan bir koleksiyon veri kaynağı olarak kullanılmaktadır. Dikkat edileceği üzere, iki adet <strong>LINQ</strong> sorgusu bulunmaktadır. Product tipinden olan generic <strong>List </strong>koleksiyonu, <strong>FillProducts </strong>metodu yardımıyla tamamen hayali veriler ile doldurulmuştur. Her iki sorguda <strong>ListPrice değeri 10' un üzerinde olan ve stokta bulunan ürünleri</strong>, <strong>adlarına göre ters sırada</strong> döndürmektedir. Ancak önemli olan nokta ikinci LINQ ifadesinde <strong>AsParallel</strong> metodunun kullanılmasıdır. Bu örnek kod parçasını çalıştırdığımda, aşağıdaki ekran görüntüsünde yer alan sonuçları aldım. </p>
<p><img src="/pics/2009%2f5%2fblg18_3.gif" alt="" /></p>
<p>Hemen şunu belirteyim. Programı yazdığım makinede <strong>çift çekirdekli Intel işlemci </strong>ve <strong>4 Gb Ram </strong>bulunmakta. İşletim sistemi olarakta <strong>Windows Vista </strong>Enterprise yer alıyor. Tabi bu örnek için Intel tabanlı işlemcinin daha büyük önem taşıdığını hemen söyleyebiliriz. Çalışma zamanındanda görüldüğü gibi, paralel olarak yürütülen LINQ ifadesi neredeyse <strong>%50</strong> daha az zamanda tamamlanmıştır. (Aslında bu kod parçasını 4 çekirdekli bir işlemcide test etmeyi çok istiyorum. Bu konuda siz değerli okurlarımın yorumlarını ve test sonuçlarını bekliyor olacağım <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> )</p>
<p>Uygulama çalışırken <strong>Task Manager</strong> aracı ile <strong>CPU</strong> kullanım durumuna baktığımda ise aşağıdaki sonuçlar ile karşılaştım.</p>
<p><img src="/pics/2009%2f5%2fblg18_4.gif" alt="" /></p>
<p>Bu ekran görüntüsünde yer alan sonuçlar tam anlamıyla durmun net analizi olmasada bir parça olsun fikir vermektedir. Yuvarlak içerisine aldığımda kısımlar, sorgunun <strong>PLINQ</strong> motoru tarafından ele alınmaya başladığı yerlerdeki ölçüm değerleridir. Dikkat edileceği üzere CPU çekirdeklerinin kullanım değerleri <strong>%100'</strong> e vurmuş durumdadır ki buda aslında, sorgunun çalıştırılması sırasında tüm işlemci gücünün kullanıldığı anlamınada gelmektedir. (Aslında Einstein' ın kuramına göre bu durum <span style="text-decoration: underline;">göreceli olarak iyi</span> sayılabilir. Ama sayılmayadabilir <img title="Undecided" src="/editors/tiny_mce3/plugins/emotions/img/smiley-undecided.gif" alt="Undecided" border="0" /> )</p>
<p>Yazdığım örnek kod parçasında işlemleri gerçekten yavaşlatmak adına bir sıralama işlemide kullandım. Anacak bunun yapılması zorunlu değildir. Özellikle sıralama kullanılmadığında sorgu çalıştırma sürelerinin birbirlerine çok yakın olduğunu gördüm. Açıkçası, <strong>PLINQ'</strong> in avantajı gerçekten çok uzun sürebilecek sorgular söz konusu olduğunda ortaya çıkmata. Bu nedenle her LINQ sorgusunun PLINQ formatına dönüştürülmesininde anlamlı <span style="text-decoration: underline;">olmadığını(olmayacağını)</span> söyleyebiliriz. Nitekim, bazı durumlarda herşey tersine dönebilir. Örneğin aşağıdaki kod parçasını göz önüne alalım.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">int[] values = new int[100];Random rnd = new Random();
for (int i = 1; i < values.Length; i++)
{
values[i] = rnd.Next(1, 1000);
}
Stopwatch watch3 = Stopwatch.StartNew();
var result3 = from value in values
where value % 2 == 0
select value;
Console.WriteLine("Toplam {0} çift sayı var",result3.ToList().Count.ToString());
Console.WriteLine(watch3.ElapsedMilliseconds.ToString());
Stopwatch watch4 = Stopwatch.StartNew();
var result4 = from value in values.AsParallel()
where value % 2 == 0
select value;
Console.WriteLine("Toplam {0} çift sayı var", result4.ToList().Count.ToString());
Console.WriteLine(watch4.ElapsedMilliseconds.ToString());</pre>
<p>Bu kod parçasındaki LINQ sorgularında, 100 tane raslantısal ve 1 ile 1000 arasında olan tamsayı değerlerinden oluşan bir dizi içerisinde kaç çift sayı olduğu tespit edilmektedir. İkinci sorgu, PLINQ motoru tarafından ele alınmaktadır. PLINQ' in, sorguyu paralel olan iş parçalarına bölerek çalıştırdığı düşünüldüğünde, ikinci ifadenin birincisine göre çok daha hızlı çalışması gerektiği tahmin edilebilir. Ama gerçekten böylemi olacaktır. İşte sonuçlar...</p>
<p><img src="/pics/2009%2f5%2fblg18_5.gif" alt="" /></p>
<p>Aslında bu sonuç son derece doğaldır. <strong>PLINQ</strong> motoru çalışma zamanında, çekirdeklere bölünecek işler için hazırlıklar yapmalıdır, thread' leri ayarlamalıdır vb... Bu ön hazırlıklar nedeni ile zaten sorgunun sürece girmesi başlı başına bir zaman kaybı anlamına gelmektedir. Bu örnek en basit anlamda, PLINQ' in her LINQ ifadesi için ele <span style="text-decoration: underline;">alınmaması</span> gerektiğinide göstermektedir.</p>
<p>Böylece geldik bir yazımızın daha sonuna. Tatil dönüşü sonrası üzerimdeki adaptasyon bıkkınlığını hafifleten bu yazımda sizlere,<strong> .Net Framework 4.0 </strong>içerisinde artık standart olarak yer alan ve <strong>Parallel Extension </strong>mimarisinin bir parçası olan <strong>PLINQ </strong>konusunu anlatmaya çalıştım. Elbetteki PLINQ içerisindede çok daha fazlası var. Bunlarıda ilerleyen yazılarımda aktarmaya çalışıyor olacağım. Sizlerde <a title="Parallel Extension Blog" href="http://blogs.msdn.com/pfxteam/default.aspx" target="_blank">bu </a>adresten Parallel Extension ile ilişkili son bilgileri alabilirsiniz. Hatta şu saatlerde VS 2010 ile gelen yeniliklerde anlatılmakta. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://buraksenyurt.com/pics/2009%2f5%2fHelloWorld.rar">HelloWorld.rar (21,81 kb)</a></p>2009-05-21T19:11:00+00:00plinqlinqbsenyurtBildiğiniz gibi son yazımı deniz kenarında bir kafede tatildeyken yazmıştım Wink Ama tatil bitti malesef ve tekrardan Morpheus' un sözleri kulaklarımda çınladı "Wellcome to the real world". Cry Yinede 1 haftalığınada olsa tatil yapabildiğime şükrediyorum. Gerçek dünyaya döndükten sonra tabiki bir süre adaptasyon sorunları ile karşılaşıyor insan doğal olaraktan. Bu adaptasyon sorunları içerisinde boğuşurken, neleri araştırabilirim diye düşünürken buluverdim kendimi.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=29213396-0a20-43f0-8cf7-0a3578e46fd71https://buraksenyurt.com/trackback.axd?id=29213396-0a20-43f0-8cf7-0a3578e46fd7https://buraksenyurt.com/post/PLINQ-(Parallel-LINQ)-Hello-World#commenthttps://buraksenyurt.com/syndication.axd?post=29213396-0a20-43f0-8cf7-0a3578e46fd7