https://www.buraksenyurt.com/Burak Selim Şenyurt - LINQ2011-08-10T16:05:30+00:00Matematik Mühendisi Bir Bilgisayar Programcısının NotlarıBurak Selim SenyurtBlogEngine.Net Syndication Generatorhttps://www.buraksenyurt.com/opml.axdBurak Selim SenyurtMatematik Mühendisi Bir Bilgisayar Programcısının Notlarıtr-TRBurak Selim Şenyurt0.0000000.000000https://www.buraksenyurt.com/post/Tek-Fotoluk-Ipucu-20-(Except-Sorgusu)Tek Fotoluk İpucu-20 (Except Sorgusu)2011-07-18T21:17:00+00:00bsenyurt<p>Merhaba Arkadaşlar,</p>
<p>Hemen hepimiz LINQ sorgularını kullanıyoruz(Tabi aramızda halen .Net 2.0 ve altı ile çalışan zavallılar da yok değil <img class="wlEmoticon wlEmoticon-sadsmile" style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" src="http://www.buraksenyurt.com/pics/wlEmoticon-sadsmile_5.png" alt="Sad smile" /> ) Lakin LINQ içerisinde çok enteresan extension method' lar olduğunu da biliyor muyuz? Örneğin, şehir bazındaki müşteri listesini veren bir View' un LINQ sorgusunda, belirli şehirlerin dışında kalanların kümesini almak isteyebiliriz. Aşağıdaki örnekte olduğu gibi <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" src="http://www.buraksenyurt.com/pics/wlEmoticon-winkingsmile_38.png" alt="Winking smile" /></p>
<p><a href="http://www.buraksenyurt.com/pics/PhotoTrick20.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 4px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="PhotoTrick20" src="http://www.buraksenyurt.com/pics/PhotoTrick20_thumb.png" border="0" alt="PhotoTrick20" width="638" height="761" /></a></p>
<p><a href="http://www.buraksenyurt.com/pics/2011%2f7%2fLINQThink.rar">LINQThink.rar (38,50 kb)</a></p>2011-07-18T21:17:00+00:00c#linqc# temelleribsenyurthttps://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=c1e113f7-4cd5-40de-aace-265636ed80eb11https://www.buraksenyurt.com/trackback.axd?id=c1e113f7-4cd5-40de-aace-265636ed80ebhttps://www.buraksenyurt.com/post/Tek-Fotoluk-Ipucu-20-(Except-Sorgusu)#commenthttps://www.buraksenyurt.com/syndication.axd?post=c1e113f7-4cd5-40de-aace-265636ed80ebhttps://www.buraksenyurt.com/post/Tek-Fotoluk-IpucuTek Fotoluk İpucu - 1 (Tek Where ya da n adet Where)2011-06-19T17:47:00+00:00bsenyurt<p>Merhaba Arkadaşlar,</p>
<p>Bazen bir fotoğraf bin kelimeye bedeldir derler. Bin kelime konusunda şüpheliyim ama bir fotoğrafın anlatım gücü açısından çok önemli katma değerlere sahip olduğuna inanıyorum. İşte size LINQ konusunda performans ipucu verecek bir fotoğraf. Bakalım ben de yarattığı etkiyi siz de yaratacak mı? <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" src="http://www.buraksenyurt.com/pics/wlEmoticon-winkingsmile_21.png" alt="Winking smile" /></p>
<p><a href="http://www.buraksenyurt.com/pics/photoTrick_1.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 4px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="photoTrick_1" src="http://www.buraksenyurt.com/pics/photoTrick_1_thumb.jpg" border="0" alt="photoTrick_1" width="639" height="545" /></a></p>2011-06-19T17:47:00+00:00c#linqwherebsenyurthttps://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=18e88010-edfa-4165-86bd-4d1f4c6cd21c4https://www.buraksenyurt.com/trackback.axd?id=18e88010-edfa-4165-86bd-4d1f4c6cd21chttps://www.buraksenyurt.com/post/Tek-Fotoluk-Ipucu#commenthttps://www.buraksenyurt.com/syndication.axd?post=18e88010-edfa-4165-86bd-4d1f4c6cd21chttps://www.buraksenyurt.com/post/LINQ-Sorgusumu-ForEach-Mi-Bir-Turlu-Karar-VeremedimLINQ Sorgusu mu? ForEach mi? Bir Türlü Karar Veremedim2010-05-27T20:40:00+00:00bsenyurt<p><img style="float: right;" src="/pics/2010%2f5%2fblg196_GirisNew.jpg" alt="" width="277" height="214" />Merhaba Arkadaşlar,</p>
<p>Bilim Kurgu fanatiklerinin kafasında her zaman hayranı oldukları filmlerden kesitler, sahneler kalır. Matrix filmini izleyenler eminimki Neo' ya uzatılan kırmızı ve mavi hap serenatını gayet iyi hatırlayacaktır. Morpheus haplardan birisinde Alice Harikalar Diyarının kapılarını ardına kadar açabileceğini ifade ederken, diğer hapı yuttuğunda, Neo' nun yatağında hiç bir şey olmamış gibi uyanacağını ve tüm bunların bir hayalden ibaret olduğunu düşüneceğini belirtir. Tabi Neo amacına ulaşmak için zaten hangi hapı içmesi gerektiğini biliyordur ki son bölümde aslında gerçekten hapı yutmaktadır <img title="Yell" src="/editors/tiny_mce3/plugins/emotions/img/smiley-yell.gif" alt="Yell" border="0" /></p>
<p>Bizde yazılımcılar olarak bazen karar verirken tabir yerinde ise sürüncemede kalabiliriz. Böyle durumlarda ufak tefek gözüken noktaların aslında çok büyük riskler taşıdığını da düşünmemiz gerekmektedir. Çünkü karar vermek için basit bir kaç test kodu çok işimize yarayacaktır. İşte bu yazımızda böyle bir konuya değiniyor olacağız.</p>
<p>Aslında konunun çıkış noktası <a title="Microsoft Teknoloji Günleri Akşam Sınıfı" href="https://www.buraksenyurt.com/post/Microsoft-Teknoloji-Gunleri-Aksam-Sinifinda-Bulusalim" target="_blank">Microsoft Teknoloji Günleri Akşam Sınıfındaki </a>bir meslektaşımın sorusu oldu. Değerli meslektaşım uygulama kodunda koleksiyon bazlı sorgulamaları gerçekleştirirken pek çok vakada foreach döngülerini tercih ettiğini söyledi. Tabi her durumda değil. Bende bu noktada aynı amaca hizmet eden bir <strong>LINQ</strong> sorgusu ile <strong>ForEach</strong> çalışması arasındaki performans farklılıklarını irdelemeye karar verdim. Nitekim performans her zaman için karar vermeden önem arz eden kriterlerden birisidir. Anlayacağınız basit bir test ve sonuçlarını irdeliyor olacağız bu kısa yazımızda.</p>
<p>Örnek uygulamamızda <strong>Enumerable.Range</strong> metodu yardımıyla elde edilen bir <strong>int</strong> sayı dizisi içerisinde <strong>2</strong> ile tam bölünebilen sayıların adedini hesap ettirmekteyiz. Tahmin edeceğiniz üzere bu tip bir işlemi <strong>LINQ</strong> sorgusu yardımıyla anlamlı bir kod ifadesi ile yerine getirebiliriz. Ayrıca bunu bir <strong>foreach</strong> döngüsü ile de gerçekleştirebiliriz. İşte test kodlarımız.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace LINQForEachPerformance
{
class Program
{
static void Main(string[] args)
{
for (int i = 1; i < 10; i++)
{
IEnumerable<int> range = Enumerable.Range(i,(i+1)*10000000);
WithLinq(range);
WithForeach(range);
}
}
static void WithLinq(IEnumerable<int> range)
{
Stopwatch sWatch = new Stopwatch();
sWatch.Start();
int count = (from i in range
where i % 2 == 0
select i).Count<int>();
Console.WriteLine(count.ToString());
sWatch.Stop();
Console.WriteLine("LINQ Total Time : {0}",sWatch.ElapsedMilliseconds.ToString());
}
static void WithForeach(IEnumerable<int> range)
{
Stopwatch sWatch = new Stopwatch();
sWatch.Start();
int count = 0;
foreach (int i in range)
{
if (i % 2 == 0)
count++;
}
Console.WriteLine("{0}",count.ToString());
sWatch.Stop();
Console.WriteLine("ForEach Total Time : {0}", sWatch.ElapsedMilliseconds.ToString());
}
}
}</pre>
<p>Örnekte <strong>arka arkaya 10 deneme</strong> yapılmaktadır. <strong>WithLinq</strong> metodu <strong>LINQ</strong> sorgusunu kullanarak ikiye tam bölünen sayıların adedini vermektedir. <strong>WithForeach</strong> metodu ise aynı işlemi <strong>foreach </strong>döngüsü yardımıyla gerçekleştirmektedir. <strong>Stopwatch</strong> tipi yardımıyla her hesaplamanın toplam süresi bulunmaktadır. Uygulamanın <strong>Intel çift çekirdek işlemcili, 4Gb Ram'</strong> i olan makinemdeki çalışma zamanı sonuçlarından bir tanesi aşağıdaki ekran görütüsündeki gibidir.</p>
<p><img src="/pics/2010%2f5%2fblg196_FirstReport.gif" alt="" /></p>
<p>Aslında her zaman için süreler farklı olacaktır ancak grafiksel eğriler benzer olacaktır. Durumun daha net bir şekilde görülmesi için değerlerin <strong>Excel</strong> üzerinde <strong>Chart </strong>olarak gösterilmesi yeterlidir. İşte sonuçlar.</p>
<p><img src="/pics/2010%2f5%2fblg196_ExcelReport.gif" alt="" /></p>
<p>Görüldüğü üzere <strong>foreach </strong>döngüsü ile yapılan hesaplamalar değer aralığı büyüse dahi <strong>LINQ</strong> sorgusuna göre daha kısa sürede icra edilmektedir. Buna göre <strong>foreach' </strong>in daha hızlı olduğunu söyleyebilir miyiz? Bu senaryo için evet. <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> Ama bildiğiniz üzere <strong>LINQ</strong> daha karmaşık sorgular yazılması noktasında elbetteki iç içe geçecek sayısız <strong>foreach</strong> kullanımından çok daha etkili bir yöntemdir. Ancak başta da belirttiğimiz gibi insan bir an için hangi hapı yutacağına karar veremiyor. Tabi farklı sorgulama senaryoları ile farklı denemeler yaparak karşılaştırmalara devam etmekte yarar olabilir. Bu kutsal görevi de siz değerli okurlarıma bırakıyorum. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://www.buraksenyurt.com/pics/2010%2f5%2fLINQForEachPerformance.rar">LINQForEachPerformance.rar (23,30 kb)</a><strong> [Örnek Visual Studio 2010 Ultimate ile geliştirilmiş ve test edilmiştir]</strong></p>2010-05-27T20:40:00+00:00c#linqforeachlinq vs foreachbsenyurtBilim Kurgu fanatiklerinin kafasında her zaman hayranı oldukları filmlerden kesitler, sahneler kalır. Matrix filmini izleyenler eminimki Neo' ya uzatılan kırmızı ve mavi hap serenatını gayet iyi hatırlayacaktır. Morpheus haplardan birisinde Alice Harikalar Diyarının kapılarını ardına kadar açabileceğini ifade ederken, diğer hapı yuttuğunda, Neo' nun yatağında hiç bir şey olmamış gibi uyanacağını ve tüm bunların bir hayalden ibaret olduğunu düşüneceğini belirtir. Tabi Neo amacına ulaşmak için zaten hangi hapı içmesi gerektiğini biliyordur ki son bölümde aslında gerçekten hapı yutmaktadırhttps://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=f356478f-2512-47ca-8ec9-00402353cbe310https://www.buraksenyurt.com/trackback.axd?id=f356478f-2512-47ca-8ec9-00402353cbe3https://www.buraksenyurt.com/post/LINQ-Sorgusumu-ForEach-Mi-Bir-Turlu-Karar-Veremedim#commenthttps://www.buraksenyurt.com/syndication.axd?post=f356478f-2512-47ca-8ec9-00402353cbe3https://www.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://www.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://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=ed839f1d-5a9b-4da2-a6f8-002e3afe68b10https://www.buraksenyurt.com/trackback.axd?id=ed839f1d-5a9b-4da2-a6f8-002e3afe68b1https://www.buraksenyurt.com/post/PLINQ-ForAll#commenthttps://www.buraksenyurt.com/syndication.axd?post=ed839f1d-5a9b-4da2-a6f8-002e3afe68b1https://www.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://www.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://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=80463ba2-920e-40ca-88ee-f96ccec184980https://www.buraksenyurt.com/trackback.axd?id=80463ba2-920e-40ca-88ee-f96ccec18498https://www.buraksenyurt.com/post/Paralel-Sorgularda-Istisna-Yonetimi(Exception-Handling)#commenthttps://www.buraksenyurt.com/syndication.axd?post=80463ba2-920e-40ca-88ee-f96ccec18498