Tpl | Engin Polat\'ın Windows 8 , Windows Phone 8 ve C# içerikli programcılık sitesi

Arşiv

Etiketlenen yazılar tpl

Uygulamalar Windows Phone 8 ile (çok) daha hızlı

13 December 2012 Yorum yapılmamış

Windows Phone 7.X kullanıcılarının en çok şikayet ettiği konulardan biri uygulamaların yeterince hızlı başlatılamaması idi. Microsoft, Windows Phone 8 tanıtımından beri yayınlanan bildirilerde uygulama başlangıç sürelerinin yaklaşık yarı yarıya azaldığını söylüyor.

Hızlı başlangıç süreleri, az pil tüketimi ve toplamda performans konularını inceleyelim;

.Net Framework, CoreCLR ve Garbage Collector

Windows Phone 8 ile birlikte en güncel versiyon olan .Net Framework 4.5 geliyor. Framework’te yapılan (hemen hemen) tüm güncellemeler ve iyileştirmelerden hem uygulama geliştirici hem de son kullanıcı olarak faydalanabiliyoruz.

Ayrıca Windows Phone 8, öncüllerinden farklı olarak .Net Compact Framework yerine CoreCLR motoru içeriyor.

CoreCLR .Net Framework 4.5 CLR ile (hemen hemen) aynı özellikleri ve optimizasyonları içerir, .Net Compact Framework‘ten çok daha verimli ve daha hızlıdır.

Özellikle Garbage Collector performansı hissedilebilir şekilde arttırılmıştır. Oyunlar gibi saniyedeki işlem adedi yüksek olan uygulamalarda Garbage Collector‘daki performans artışı uygulamanın toplam performansına büyük etki eder.

Async Framework

.Net Framework 4.5‘teki en önemli yeni gelişme C# 5 ve VB.Net 11 tarafından tanıtılan yeni asenkron programlama modelidir.

CoreCLR ve .Net Framework kütüphanelerinde yapılan güncellemeler ile birlikte Windows Phone 8 asenkron programlama modelinin tüm nimetlerinden faydalanabiliyor.

Windows Phone 8 cihazların çok çekirdekli işlemciye sahip olması, async, await anahtar kelimelerinin ve Task Parallel Library kullanımının uygulamaların başlangıç ve kullanım hızlarının artmasına katkısı büyük.

Asenkron kütüphanelerin (hemen hemen) tamamı .Net Framework içerisine gömülmüş durumda. Fakat bazı kütüphanelere async desteğinin (özellikle System.Net namespace’i altındakiler) NuGet aracılığı ile indirilmesi gerekiyor.

Microsoft.Bcl.Async paketini NuGet üzerinden indirebilirsiniz. Daha ayrıntılı bilgi için MSDN’deki BCL Blog makalesini okumanızı tavsiye ederim.

Cloud Derleyici ile çok daha hızlı kod

Windows Phone 8‘de yüksek performans ve pil ömründen tasarruf için çok daha uygun olan yeni bir kod oluşturma yaklaşımı benimsenmiş.

Uygulamaları son kullanıcı cihazlara indirilmeden önce Windows Phone Store tarafından yüksek kalitede ARM koduna derleniyorlar.

Bu sayede Windows Phone 7.X cihazlar için uygulamanın her çalıştırılması esnasında yapılan derleme işlemi, Windows Phone 8 cihazlar için gerçekleştirilmiyor.

CPU yükünü artıran ve pil tüketimine olumsuz etkisi bulunan bu işlemin aradan çıkartılmış olması Windows Phone 8 cihazlarda uygulamaların daha hızlı başlatılmasını ve pil tüketimlerinin azalmasını sağlamış.

Microsoft pre-compile (ön-derleme) sürecini son kullanıcı cihazdan alarak Washington Columbia nehri üzerine kurdukları bir jeneratör aracılığı ile beslenen bir sisteme devretmiş durumda.

Not : Cep telefonu pili yerine enerjinin bir nehirden sağlanması iyi düşünülmüş.

Windows 8 Metro Style Uygulamalarda Async Desteği

17 November 2011 1 yorum

Windows 8 Programlama makale serisine, Async Desteği ile devam ediyoruz.

Asenkron programlama ölçeklendirilebilir ve yanıt veren (donmayan) uygulama geliştirmek için uzun yıllardır bilinen bir teknik. Uzun yıllardır bilinmesine rağmen, uygulama geliştiriciler olarak asenkron programlama bize hep zor gelmiştir.

.Net 4.5 ile birlikte asenkron programlama Async Framework sayesinde kolay programlanabilir hale getirildi ve Task Parallel Library‘nin (TPL) içerisine entegre edildi.

Asenkron programlama ile ilgili daha detaylı bilgiye, MSDN‘in Visual Studio Asynchronous Programming sayfasından ulaşabilirsiniz.

Bu makalede basit bir örnek ile async ve await anahtar kelimelerinin kullanımını inceleyeceğiz.

Yapacağımız örnek bir web sitesinin içeriğini okuyacak ve web adreslerini toplayacak. İlk olarak standart programlama yöntemlerini kullanarak uygulamamızı geliştireceğiz, daha sonra async ve await anahtar kelimeleri ile asenkron programlama öğelerini uygulamamıza dahil edeceğiz.

Hemen yeni bir Visual Studio 2011 açarak geliştirmeye başlayalım;

Yeni Proje oluşturma dialog kutusunda Windows Metro Style grubunda yer alan Application proje şablonunu seçelim ve projemize bir isim verelim (bu örnekte benim kullandığım isim, AsyncOrnek)

Proje oluşturulduğunda MainPage.xaml dosyasının içeriği;

<UserControl x:Class="Windows8ApplicationBar.MainPage"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
	mc:Ignorable="d"
	d:DesignHeight="768" d:DesignWidth="1366">

	<Grid x:Name="LayoutRoot" Background="#FF0C0C0C">
	</Grid>

</UserControl>

İlk önce uygulamamıza bir TextBox, bir Button ve bir ListBox nesnesi ekliyoruz;

<Grid x:Name="LayoutRoot" Background="#FF0C0C0C">

	<TextBox x:Name="txtKaynakHtml" Width="600" Height="700" HorizontalAlignment="Left" />
	<ListBox x:Name="lbUrlList" Width="600" Height="700" HorizontalAlignment="Right" />
	<Button x:Name="btnTara" Content="Tara" HorizontalAlignment="Center" />

</Grid>

Böylece uygulama ekranımız şu şekilde gözüküyor;

TextBox kontrolünün Text özelliğine web sitesinin kaynak html’ini atayacağımız için, çok satır gösterebilir olması lazım (MultiLine)

WPF TextBox kontrolünün MultiLine olabilmesi için, TextBox element’ine şu özellikleri ekliyoruz;

TextWrapping="Wrap" AcceptsReturn="True" ScrollViewer.VerticalScrollBarVisibility="Visible"

Button kontrolüne basıldığında tarama işlemini başlatmak için, Button element’inde Click olayını yakalıyoruz;

Click="btnTara_Click"

Böylece uygulamamızın XAML kod’u aşağıdaki hale gelmiş oluyor;

<UserControl x:Class="AsyncOrnek.MainPage"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
	mc:Ignorable="d"
	d:DesignHeight="768" d:DesignWidth="1366">

	<Grid x:Name="LayoutRoot" Background="#FF0C0C0C">

		<TextBox x:Name="txtKaynakHtml" Width="600" Height="700" HorizontalAlignment="Left" TextWrapping="Wrap" AcceptsReturn="True" ScrollViewer.VerticalScrollBarVisibility="Visible" />
		<ListBox x:Name="lbUrlList" Width="600" Height="700" HorizontalAlignment="Right" />
		<Button x:Name="btnTara" Content="Tara" HorizontalAlignment="Center" Click="btnTara_Click" />

	</Grid>

</UserControl>

MainPage.xaml.cs dosyasında btnTara_Click method’unu yazıyoruz;

private void btnTara_Click(object sender, RoutedEventArgs e)
{
}

Öncelikle, taradığımız sitede bulacağımız url’leri saklayacağımız string dizisini oluşturalım;

List<string> UrlList = new List<string>();

HttpClient sınıfından yeni bir instance oluşturup, Get() method’una, tarayacağımız sitenin adresini yazalım.

Get() method’undan dönen HttpResponseMessage tipindeki cevabı bir değişkene atayalım;

var HttpCagri = new HttpClient().Get("http://www.enginpolat.com");

HttpClient sınıfı System.Net.Http namespace‘inde yer aldığı için, MainPage.xaml.cs dosyasının using kısmına

using System.Net.Http;

satırını ekleyelim.

HttpCagri değişkeninin sitenin kaynak html’ini okuyabildiğinden emin olmak için, EnsureSuccessStatusCode() method’unu çağıralım.

Böylece HttpContent tipindeki Content özelliğine erişebilir olacağız. Content özelliğinin ReadAsString() method’u kaynak html’ini döndürecek, biz de bir değişken aracılığıyla bu html’i saklayacağız.

var KaynakHtml = HttpCagri.EnsureSuccessStatusCode().Content.ReadAsString();

Elimizdeki bu html verisini, arayüzdeki txtKaynakHtml TextBox‘ında göstermek için;

txtKaynakHtml.Text = KaynakHtml;

Şimdi yapmamız gereken, KaynakHtml değişkenindeki url‘leri bulmak. Bunun için Regex sınıfından faydalanacağız ve yazacağımız Regular Expression‘a uyan url’leri UrlList değişkeninde biriktireceğiz.

Regex sınıfı System.Text.RegularExpressions namespace’inde olduğu için, MainPage.xaml.cs dosyasının using kısmına

using System.Text.RegularExpressions;

satırını ekleyelim.

Öncelikle Regex sınıfının static Matches method’una KaynakHtml değişkenini, Regular Expression metnini ve arama yaparken büyük/küçük harf ayrımı yapmaması için RegexOptions.IgnoreCase değerini parametre olarak veriyoruz.

RegexOptions parametresine verebileceğimiz diğer değerler;

  • RegexOptions.None
  • RegexOptions.IgnoreCase
  • RegexOptions.Multiline
  • RegexOptions.ExplicitCapture
  • RegexOptions.Compiled
  • RegexOptions.Singleline
  • RegexOptions.IgnorePatternWhitespace
  • RegexOptions.RightToLeft
  • RegexOptions.ECMAScript
  • RegexOptions.CultureInvariant

Method’dan dönen MatchCollection tipindeki cevabı bir değişkende saklıyoruz;

var mc = Regex.Matches(KaynakHtml, "href\\s*=\\s*(?:\"(?<1>http://[^\"]*)\")", RegexOptions.IgnoreCase);

Bir foreach döngüsü ile MatchCollection‘daki her Match‘i UrlList‘e ekliyoruz;

foreach (Match m in mc)
{
	UrlList.Add(m.Groups[1].Value);
}

Son olarak arayüzdeki lbUrlList ListBox‘ında bu listeyi gösteriyoruz;

lbUrlList.ItemsSource = UrlList;

İlk çalıştırma aşamasına geldik. Projeyi çalıştırıp Tara butonuna bastığımızda garip bir hata alıyoruz;

Cannot write more bytes to the buffer than the configured maximum buffer size: 65536

Bu hataya, kaynak html’ini aldığımız siteden dönen cevabın 65536 karakterden büyük olması yol açıyor. Çözüm aslında basit;

HttpClient tipindeki değişkenin MaxResponseContentBufferSize özelliğine sitenin kaynak html’inin karakter sayısı kadar büyük bir değer vermemiz lazım.

Bu örnek için ben verilebilecek en büyük değer olan int.MaxValue değerini seçtim, HttpCagri değişkenini tanımladığımız satırı şöyle güncelliyoruz;

var HttpCagri = new HttpClient() { MaxResponseContentBufferSize = int.MaxValue }.Get("http://www.enginpolat.com");

Artık projemizi çalıştırabiliriz;

Buraya kadar uygulamayı çalıştırmaya odaklanmıştık, uygulamayı çalıştırdıktan sonra kullanıyoruz ve farkediyoruz ki, Tara butonuna bastıktan sonra liste dolana kadar uygulama kullanıcıya yanıt vermiyor.

Kullanıcı dostu bir uygulamanın her zaman kullanıcıya yanıt vermesi beklenir. Biz de Tara butonunun yaptığı işi asenkron yapmasını sağlayarak oluşan donmaların önüne geçebiliriz.

Asenkron çalışma yeteneğini eklemek için öncelikle btnTara_Click method’una async anahtar kelimesini ekleyeceğiz;

private async void btnTara_Click(object sender, RoutedEventArgs e)

Uygulamanın donmasına sebep olan en uzun iş, internet sitesinin cevabının alındığı HttpClient sınıfının Get() method’u. Bu yüzden Get() method’unu asenkron özellikte olan GetAsync() method’u ile değiştiriyoruz.

HttpCagri değişkenine değer atamadan önce await anahtar kelimesi ile asenkron yaptığımız çağrının sonuçlanmasını beklemeliyiz. İlgili satırı aşağıdaki şekilde güncelleyelim;

var HttpCagri = await new HttpClient() { MaxResponseContentBufferSize = int.MaxValue }.GetAsync("http://www.enginpolat.com");

Böylece uygulamamıza asenkron çalışabilme yeteneğini kazandırmış olduk. Projenin kodlarının tamamı;

<UserControl x:Class="AsyncOrnek.MainPage"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
	mc:Ignorable="d"
	d:DesignHeight="768" d:DesignWidth="1366">

	<Grid x:Name="LayoutRoot" Background="#FF0C0C0C">

		<TextBox x:Name="txtKaynakHtml" Width="600" Height="700" HorizontalAlignment="Left" TextWrapping="Wrap" AcceptsReturn="True" ScrollViewer.VerticalScrollBarVisibility="Visible" />
		<ListBox x:Name="lbUrlList" Width="600" Height="700" HorizontalAlignment="Right" />
		<Button x:Name="btnTara" Content="Tara" HorizontalAlignment="Center" Click="btnTara_Click" />

	</Grid>

</UserControl>
private async void btnTara_Click(object sender, RoutedEventArgs e)
{
	List<string> UrlList = new List<string>();

	var HttpCagri = await new HttpClient() { MaxResponseContentBufferSize = int.MaxValue }.GetAsync("http://www.enginpolat.com");
	var KaynakHtml = HttpCagri.EnsureSuccessStatusCode().Content.ReadAsString();

	txtKaynakHtml.Text = KaynakHtml;

	var mc = Regex.Matches(KaynakHtml, "href\\s*=\\s*(?:\"(?<1>http://[^\"]*)\")", RegexOptions.IgnoreCase);

	foreach (Match m in mc)
	{
		UrlList.Add(m.Groups[1].Value);
	}

	lbUrlList.ItemsSource = UrlList;
}

Şubat 2010 Seminerleri / C# 4.0 Yenilikleri – 2

19 February 2010 2 yorum

BilgeAdam Kadıköy Şubesinde gerçekleştirdiğim Şubat Seminerlerinin ikincisinin prezentasyonuna ve proje kodlarına buradan erişebilirsiniz.

Bu seminerde değindiğim konular;

  • Dynamics (DLR)
  • Lazy Sınıfı
  • COM İyileştirmeleri
  • Task Parallel Library (TPL)
  • ASP.NET 4.0 Yenilikleri
  • SEO İyileştirmeleri
  • Dynamic Data Web Site

Powerpoint Prezentasyonu

Visual Studio 2010 Kodları

Normal For ve Paralel For Döngülerinin Karşılaştırması

08 December 2009 Yorum yapılmamış

Yazdığımız uygulamaların olmazsa-olmaz’larından birisi de, for döngüleridir.

Ne kadar basit’te olsa, ne kadar karmaşık’ta olsa, mutlaka uygulamalarımızda for döngülerine ihtiyaç duyarız ve sıklıkla kullanırız.

Bu makaleyi okumaya devam etmeden önce, .Net Framework 4.0 ile birlikte gelecek olan Task Parallel Library hakkında yazdığım şu yazıyı (TPL (Task Parallel Library) – Task Class) okumanızı tavsiye ederim.

Task Parallel Library ile gelen Parallel sınıfının For methodunu kullanarak, Multi-Core destekli for döngüleri oluşturabiliriz.

Multi-Core destekli olması, Multi-CPU (birden çok CPU içeren) bilgisayarlarda, döngünün CPU’lara dağıtılabilmesini sağlıyor.

Parallel Library‘den önce for döngüsü;

//10 adımlı döngü (0 dahil, 10 hariç)
for (int iLoop = 0; iLoop < 100; iLoop++)
{
	// Yapılacak İş
}

Parallel Library ile for döngüsü;

//10 adımlı döngü (0 dahil, 10 hariç)
Parallel.For(0, 10, iLoop => {
	// Yapılacak İş
});

Parallel.For metodunu kullarak örnek bir proje hazırladım, projenin kaynak kodlarına buradan ulaşabilirsiniz.

NormalFor_ParallelFor_1

Uzun tek bir döngü yazmak yerine, içiçe iki döngü yazdım, böylece, CPU ve İşletim Sistemi’nin çok adımlı döngülerde yaptığı iyileştirmeleri bir miktar azaltmayı ve daha doğru bir sonuç elde etmeyi amaçladım.

Döngülerden bir tanesini gene de uzun tuttum (100.000.000 – Yüz Milyon Adım), böylece, eğer Framework’ün kendisi döngülerde iyileştirme yapıyorsa, bunları yakalamayı hedefledim.

Diğer döngüyü ise nispeten daha kısa (500 – Beş Yüz) tuttum.

NormalFor_ParallelFor_2

Böylece toplamda 50.000.000 (Elli Milyar) adımlı döngü oluşmuş oluyor.

Gelelim, kodlara;

private void btnNormalDongu_Click(object sender, EventArgs e)
{
	int Sayac = 0;
	Stopwatch sw = Stopwatch.StartNew();
	for (int iLoop = 0; iLoop < (int)txtTekrarAdedi.Value; iLoop++)
	{
		for (int yLoop = 0; yLoop < (int)txtDonguAdedi.Value; yLoop++)
		{
			Sayac++;
		}
	}
	sw.Stop();

	lblNormalDonguSonuc.Text = string.Format("{0:0,0} ms.", sw.ElapsedMilliseconds);
}

ve

private void btnParalelDongu_Click(object sender, EventArgs e)
{
	int Sayac = 0;
	Stopwatch sw = Stopwatch.StartNew();
	Parallel.For(0, (int)txtTekrarAdedi.Value, i => {
		Parallel.For(0, (int)txtDonguAdedi.Value, y => {
			Sayac++;
		});
	});
	sw.Stop();

	lblParalelDonguSonuc.Text = string.Format("{0:0,0} ms.", sw.ElapsedMilliseconds);
}

Teker teker butonlara bastığımızda, for döngüleri çalışacak ve sonuçları Label’larda göreceğiz.

Uygulamayı kendi bilgisayarımda çalıştırdığımda aldığım sonuçlar;

NormalFor_ParallelFor_3

Normal for döngüsü: 888.700 ms. (yaklaşık 14 dakika 48 saniye)

Paralel for döngüsü: 219.326 ms. (yaklaşık 3 dakika 39 saniye)

Aradaki fark: 75%

Uygulamayı çalıştırdığım bilgisayarın özellikleri;

NormalFor_ParallelFor_4

TPL (Task Parallel Library) – Task Class

06 December 2009 Yorum yapılmamış

.Net 4.0 ile birlikte gelecek güzel class’lardan bir tanesi de Task class’ı.

Task class’ı ve TPL (Task Parallel Library) ile birlikte gelen diğer class’lar sayesinde paralel programlama .net framework ile desteklenir hale geliyor.

TPL_Task_1

Yandaki görselde görebileceğiniz gibi, TPL (Task Parallel Library) ve PLINQ (Parallel LINQ) .Net Framework 4.0 ile gelen en önemli özellikler.

Paralel programlamanın performans’a katkısını MSDN’de yer alan şu iki makale’de okuyabilirsiniz;

Parallel Programming in .Net Framework

Parallel Performance

Gene MSDN’de yer alan şu sayfalardan da .net 4 ile gelecek yeni yapıları öğrenebilirsiniz;

Data Structures for Parallel Programming

Task Parallelism (Task Parallel Library)

Introduction to Tasks

Task class’ını kullanarak, Thread yönetme maliyetlerinden kurtularak kolaylıkla Multi-Core uyumlu, Asenkron çalışabilen kodlar yazabiliriz.

Task class’ından yeni bir örnek oluşturmak için;

Aşağıdaki gibi yeni bir instance oluşturup, daha sonra Start method’u ile başlatabiliriz.

Task t0 = new Task(() =>
	MessageBox.Show("Task Örneği 1")
);
t0.Start();

Veya, aşağıdaki kodda yazdığım gibi, Task class’ının singleton static Factory property’sinin StartNew method’u ile hem tanımlayıp, aynı anda başlatabiliriz.

Task t1 = Task.Factory.StartNew(() =>
{
	string Mesaj = "Birinci çalışacak..";
	MessageBox.Show(Mesaj);
});

Örneğini oluşturduğumuz Task nesnesi, başlatılana kadar hafızada bekler. Başlatıldığında, ayrı bir thread’de çalışacağından dolayı, uzun süren işlerin arayüz’ü kilitlemesini önlemek için kullanılabilir.

Birden Fazla Task’ın peşpeşe çalışması sağlanabilir;

Task t2 = Task.Factory.StartNew(() =>
{
	MessageBox.Show("Birinci çalışacak..");
}).ContinueWith((t) =>
{
	MessageBox.Show("İkinci çalışacak..");
}).ContinueWith((t) =>
{
	MessageBox.Show("Üçüncü çalışacak..");
});

Veya birden fazla Task’ın aynı anda çalışması da sağlanabilir;

Task t3 = Task.Factory.StartNew(() =>
{
	Task c1 = Task.Factory.StartNew(() =>
	{
		MessageBox.Show("Aynı anda çalışacak..");
	}, TaskCreationOptions.AttachedToParent);

	Task c2 = Task.Factory.StartNew(() =>
	{
		MessageBox.Show("Aynı anda çalışacak..");
	}, TaskCreationOptions.AttachedToParent);
});

TaskCreationOptions parametresine verdiğimiz AttachedToParent değerine dikkat!.. Bu sayede c1 ve c2 Task’ları t3 Task’ının Child Task‘ları haline geldi, t3 Task’ı da Parent Task oldu.