BilgeAdam’da öğrencilerime WinForms anlatırken, kafalarının çok karıştığı konulardan biri de Timer nesnesidir.
Daha doğrusu Timer nesneleridir demeliyim. Çünkü .Net Framework’te Timer ismine sahip tam 3 tane class var;
Özellikle Multi-Threaded uygulamalarda tercih edilir. Thread-safe olduğu için, birden çok thread’den erişilebilir.
System.Timers.Timer t = new System.Timers.Timer(5000); t.Elapsed += delegate(object _s, System.Timers.ElapsedEventArgs _e) { MessageBox.Show(“5 saniye geçti!..”); t.Stop(); }; t.Start();</pre> System.Threading.Timer
TimerCallBack delegate kullanarak, atanmış metodu çalıştırabilir. Metod, framework tarafından oluşturulan başka bir thread’de çalışır.
Timer nesnesi oluşturulduğu anda, çalışmaya başlar ve scope’tan çıkana kadar da çalışır. Durdurmak veya Başlatmak mümkün değildir.
Aşağıdaki örnekte 2.parametre (null), Callback method’a aktarılacak parametreyi gösterir.
3.parametre (1000), Timer nesnesi başlatılmadan önce beklenecek süreyi gösterir.
System.Threading.Timer t = new System.Threading.Timer(new System.Threading.TimerCallback(TimerTest), null, 1000, 5000);
private void TimerTest(object state) { MessageBox.Show("5 saniye geçti!.."); }
Toolbox’ta gördüğümüz nesnedir. Windows Form ile aynı thread’de ve senkron olarak çalışır, böylece hiçbir UI operasyonunu bölmez.
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer(); t.Interval = 5000; t.Start(); t.Tick += delegate(object _s, EventArgs _e) { MessageBox.Show("5 saniye geçti!.."); t.Stop(); }; Daha ayrıntılı bilgi için MSDN'deki şu makaleyi okuyabilirsiniz.
Database işlemleri gerçekleştiren bir web service yazıyorsunuz. Faturalama ihtiyaçlarından dolayı, her kullanıcının web service’i kullanma miktarını hesaplamanız gerekiyor.
Kullanıcıların web service’e her erişmesiyle değeri 1 artırılacak session değişkeni kullanmayı planlıyorsunuz.
Web Method içerisinde session değişkeni kullanmadan önce ne yapılmalı?
Doğru cevap; WebMethod attribute’üne EnableSession = true eklenmeli
EnableSession = true Web Method‘un session değişkenlerine erişebilmesini sağlar. Eğer bu parametreyi true yapmazsanız, session değişkenleri herzaman null (VB.NET’te Nothing) döndürecektir.
<sessionstate = “InProc” /> varsayılan konfigürasyondur. web.config dosyasında bu satırın bulunması session değşikenlerine erişim sağlamaz.
InProc değeri ile session değişkenlerinin, web sunucusunun hafızasında (Ram Bellek) bulundurulacağı belirtilmiş olur. Bu değeri SQL Server veya State Server değerleri ile değiştirebilirsiniz.
CacheDuration, cache mekanizmasını konfigüre eder, session ile alakalı değildir.
TransactionOption = TransactionOption.Supported, Transaction desteğini aktif hale getirir, session ile alakalı değildir.
Bu yazımda, Twitter‘da arama yapan bir uygulama yazacağım. Siz de yazıyı baştan sona takip ederek, kendi twitter arama uygulamanızı yazabilirsiniz.
Hemen ekran tasarımımızı yapmakla işe başlayalım;
Sayfadaki elemanlar;
Search fonksiyonu geriye JSON formatında bilgi döndürüyor. Uygulamalarınızda JSON verilerini kullanabilmek için, şu sayfadan bulabileceğiniz JSON parser class’ını kullanabilirsiniz.
Şimdi, butonların (btnArama, btnGeri, btnIleri) Click olayını yazalım;
private void btnArama_Click(object sender, EventArgs e) { txtSayfa.Text = “1”; AramaYap(); }</pre>
private void btnGeri_Click(object sender, EventArgs e) { int Sayfa = Convert.ToInt32(txtSayfa.Text) - 1; txtSayfa.Text = Sayfa < 1 ? "1" : Sayfa.ToString(); AramaYap(); }
private void btnIleri_Click(object sender, EventArgs e) { txtSayfa.Text = (Convert.ToInt32(txtSayfa.Text) + 1).ToString(); AramaYap(); }
Butonların Click olaylarının kalbinde AramaYap() methodu yatıyor. Hemen yazalım;
private void AramaYap() { flowLayoutPanel1.Controls.Clear(); WebRequest wr = WebRequest.Create(string.Format("http://search.twitter.com/search.json?q={0}&rpp={1}&page={2}", txtArama.Text, txtSonucAdet.Value, txtSayfa.Text)); Stream s = wr.GetResponse().GetResponseStream(); StreamReader sr = new StreamReader(s); string Sonuc = sr.ReadToEnd(); Hashtable hs = (Hashtable)JSON.JsonDecode(Sonuc); foreach (Hashtable oItem in (ArrayList)hs["results"]) flowLayoutPanel1.Controls.Add(CreateTwitItem(oItem)); }
AramaYap() method’unda ilk iş, flowLayoutPanel’i temizliyoruz.
Daha sonra, Twitter Search API‘den öğrendiğimiz gibi, http://search.twitter.com/search.json adresine uygun parametreler ile sorgu atıyoruz.
Gelen bilgi JSON formatında olduğu için, JSON parser class’ımızı kullanıyoruz (JSON.JsonDecode) ve sonuç bilgisini Hashtable formatına çeviriyoruz.
Hashtable‘ın results öğesi ArrayList formatındadır ve arama sonucunun herbir satırını ifade etmektedir. Bu yüzden basit bir foreach döngüsü ile flowLayoutPanel’e ekleme yapıyoruz.
flowLayoutPanel’e ekleyeceğimiz her nesne CreateTwitItem fonksiyonunda oluşturuluyor;
private Panel CreateTwitItem(Hashtable TwitItem) { Panel p = new Panel(); string from_user = TwitItem["from_user"] != null ? TwitItem["from_user"].ToString() : ""; string to_user = TwitItem["to_user"] != null ? TwitItem["to_user"].ToString() : ""; string text = TwitItem["text"] != null ? TwitItem["text"].ToString() : ""; string profile_image_url = TwitItem["profile_image_url"] != null ? TwitItem["profile_image_url"].ToString() : ""; string tweet_id = TwitItem["id"] != null ? TwitItem["id"].ToString() : ""; DateTime created_at = TwitItem["created_at"] != null ? DateTime.Parse(TwitItem["created_at"].ToString()) : DateTime.Now; string twitter_url = string.Format("http://twitter.com/{0}/statuses/{1}", from_user, tweet_id); p.Size = new Size(flowLayoutPanel1.Width - 23, 60); p.BorderStyle = BorderStyle.FixedSingle; PictureBox pb = new PictureBox(); pb.Dock = DockStyle.Left; pb.Size = new Size(50, 50); pb.BorderStyle = BorderStyle.FixedSingle; pb.Load(profile_image_url); Label l1 = new Label(); l1.AutoSize = false; l1.Location = new Point(pb.Width, 2); l1.Size = new Size(300, 15); l1.Text = string.Format("@{0} -> @{1} ({2} {3})", from_user, to_user, created_at.ToShortDateString(), created_at.ToShortTimeString()); Label l2 = new Label(); l2.AutoSize = false; l2.Location = new Point(pb.Width, 19); l2.Size = new Size(flowLayoutPanel1.Width - pb.Width - 20, 38); l2.Text = text; LinkLabel l3 = new LinkLabel(); l3.Text = "Sayfaya Git"; l3.Location = new Point(flowLayoutPanel1.Width - (l3.Width - 10), 2); l3.Click += delegate { Process.Start(twitter_url); }; p.Controls.Add(pb); p.Controls.Add(l1); p.Controls.Add(l2); p.Controls.Add(l3); p.MouseEnter += delegate { p.BackColor = Color.LightYellow; }; pb.MouseEnter += delegate { p.BackColor = Color.LightYellow; }; l1.MouseEnter += delegate { p.BackColor = Color.LightYellow; }; l2.MouseEnter += delegate { p.BackColor = Color.LightYellow; }; p.MouseLeave += delegate { p.BackColor = SystemColors.Control; }; l2.MouseLeave += delegate { p.BackColor = SystemColors.Control; }; return p; } *CreateTwitItem()* fonksiyonunda bir **Panel** nesnesi oluşturup, içerisine bir picturebox, iki label, bir linklabel ekliyoruz ve geriye Panel nesnesini döndürüyoruz. Böylece foreach'in her adımında flowLayoutPanel'e yeni Panel nesnesi ekleniyor. Uygulamamızı çalıştırıyoruz ve işte örnek ekran görüntüsü; ![TwitterSearch_2](/assets/uploads/2009/12/TwitterSearch_2.png "TwitterSearch_2") İsterseniz uygulamanın kodlarını buradan indirebilirsiniz.
WCF’teki Channel Model‘e göre, aşağıdaki Channel’lardan hangisi Channel Stack’te en alt katmandır?
Transport Layer, mesajların alıp-gönderilmesinden sorumludur ve Channel Stack’te ent alt seviyededir.
Transport Layer’ın üstünde Protocol Layer yeralır ve onun üstünde de Application vardır.
Network Interface Layer, sadece Stack bir protokolle ilişkilendirildiğinde kullanılabilir. (Mesela TCP)
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 İş }</pre> 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.
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.
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](/assets/uploads/2009/12/NormalFor_ParallelFor_3.png "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](/assets/uploads/2009/12/NormalFor_ParallelFor_4.png "NormalFor_ParallelFor_4")
Senior Software Engineer, @Microsoft
Ada ve Ege'nin babası ;)
Makale Adedi: 484