2 Ağustos 2014 Cumartesi

C# ile Asenkron Programlama

Merhaba. Bu yazımda size C# ile asenkron programlamadan(asynchronous programming) ve asenkron programlamada kontrol akışının (control flow) nasıl sağlandığından bahsedeceğim. Bana kalırsa anlaması biraz güç bir konu. Ben de bu konuyu kendi anladığım ve sizinde anlayacağınızı düşündüğüm bir şekilde izah etmeye çalışacağım. Eğer yazımda bir hata görürseniz, lütfen yorumunuzda belirtmekten kaçınmayın. Hadi o zaman başlayalım!



Asenkron Programlama Nedir?

Hepimizin başına defalarca gelen bir olay vardır. Kullandığımız programda bir butona basarsınız ve program aniden donar. Kullanıcı arayüzü (User Interface - UI) yaptığımız hiçbir işleme cevap vermez. Bir süre sonra program hiçbir şey olmamış gibi çalışmaya devam eder. Bunun sebebi arkaplanda yürütülen işleminin senkron bir şekilde gerçekleştiriliyor olmasıdır, yani program o anki işlemi tamamlamadan ne başka bir işleme devam edebilir ne de kullanıcının komutlarına cevap verebilir. Asenkron programlama burada işimize yarar. Aşağıdaki kod örneğini inceleyelim.

private void button1_Click(object sender, EventArgs e)
{
    DownloadImage();
    textBox1.Text = "Resim indirildi.";
}

private void DownloadImage()
{
     WebClient client = new WebClient();
     byte[] imageData = client.DownloadData("http://haticevarlik.azurewebsites.net/images/yaz-okuluna-dogru/SAM_0361.JPG");
     this.pictureBox1.Image = Image.FromStream(new MemoryStream(imageData));
}


Bir Windows Form uygulaması düşünün. Bu uygulamada 3 tane kontrolümüz olsun: button1, textBox1 ve pictureBox1. button1'e tıkladığımızda DownloadImage metodu çağırılacak ve bir websitesinden resim indirilecek. Resim indirildikten sonra textBox1'e "Resim indirildi" yazdırılacak. Resmin de boyutu büyük. Bu uygulamayı yazıp çalıştırdığınızda göreceksiniz ki butona bastığımız anda programda bir donma meydana geliyor ve ancak resim indirme işlemi bittikten sonra program çalışır hale gelip textBox1'ın metni değiştiriliyor. İşte bu örneğimiz senkron programlamaya bir örnektir. Herhangi bir işlem bitmeden bir sonraki işleme geçilemez ve UI kilitlenir. Şimdi bir de aşağıdaki kod örneğini inceleyelim.

private void button1_Click(object sender, EventArgs e)
{
    DownloadImage();
    textBox1.Text = "Resim indiriliyor.";
}

private async void DownloadImage()
{
    WebClient client = new WebClient();
    byte[] imageData = await client.DownloadDataTaskAsync("http://haticevarlik.azurewebsites.net/images/yaz-okuluna-dogru/SAM_0361.JPG");
    this.pictureBox1.Image = Image.FromStream(new MemoryStream(imageData));
    textBox1.Text = "Resim indirildi.";
}

Yukarıdaki kod örneğini çalıştırdığınızda göreceksiniz ki, program resmin indirilmesini beklemeden yani DownloadImage metodu tamamlanmadan textBox1'ın metnini "Resim indiriliyor" olarak değiştiriyor ve siz de bu esnada arayüzde hiçbir takılmaya ya da kilitlenmeye sebep olmadan programda istediğiniz yere tıklayıp pencereyi başka yerlere taşıyabiliyorsunuz. Resim indirme işlemi tamamlandığında ise tekrar DownloadImage metoduna dönülüyor ve kalan işlemler (pictureBox1'a resim koyma ve textBox1'ın metnini "Resim İndirildi." olarak değiştirme) tamamlanıyor. Tüm bunları asenkron programlama sayesinde gerçekleştirdik. Bir uygulamada asenkron metodları kullandığınız zaman o uygulama kullanıcı arayüzüne ve arayüzde yapılan değişikliklere tepki vermeye devam eder. İsterseniz bir pencerenin boyutunu büyütüp küçültebilir, pencereyi başka yere taşıyabilir ya da asenkron bir şekilde yürütülen işlemin bitmesini beklemeden uygulamayı kapatabilirsiniz. Şimdi dilerseniz bunun nasıl yapıldığına bakalım.

İki Anahtar Kelime: async ve await

Yukarıdaki iki ayrı programı inceleyelim. İkisinin de işlevi aynı fakat ikinci program, resmi asenkron bir şekilde indiriyor. Bunu async/await anahtar kelimelerini (keyword) ve DownloadData metodu yerine DownloadDataTaskAsync metodunu kullanarak gerçekleştiriyor. async ve await anahtar kelimeleri asenkron programlamanın merkezindedir. Bu kelimeleri kullanarak bir metodu asenkron hale getirebilirsiniz. Şimdi asenkron programlamada kontrol akışının nasıl sağlandığına bakalım.

Asenkron Programlamada Kontrol Akışı

Asenkron programlamayı kullanarak resim indirdiğimiz program üzerinden kontrol akışının nasıl olduğuna maddeler halinde bakalım:

  1. button1'a tıklandığında button1_click metoduna giriliyor ve DownloadImage metodu çağrılıyor.
  2. Kontrol button1_click'den DownloadImage metoduna geçiyor. async anahtar kelimesi derleyiciye metodun await anahtarını içerdiğini haber veriyor.
  3. client isminde bir WebClient nesnesi (object) oluşturuluyor.
  4. Parametre olarak girilen kaynaktan resim indirme işlemi başlatılıyor. Fakat bu satırda await kullanıldığı için DownloadImage methodu askıya alınıyor(suspend) ve kontrol tekrar "caller" metodumuz olan olan button1_click metoduna dönüyor.
  5. textBox1'in text'i "Resim İndiriliyor." olarak değiştiriliyor. Devamında başka kodlar olmadığı için resim indirme işlemi bitene kadar kontrol bu metodda kalıyor.
  6. Resim indirme işlemi tamamlandığında kontrol tekrar DownloadImage metoduna dönüyor ve metod kaldığı yerden çalışmaya devam ediyor. pictureBox1 kontrolüne resim ekleniyor ve textBox1'ın text'i "Resim İndirildi." olarak değiştiriliyor. Böylelikle her iki methoddaki kodların tamamı çalıştırılmış oluyor.
Sonuç

Asenkron metodlar kullanmak iyi bir kullanıcı deneyimi oluşturmak için artık olmazsa olmazlardan. C# 5.0 ile gelen async ve await anahtarları asenkron metod yazmayı oldukça kolaylaştırıyor. Tabi ki asenkron programlama bu kadarla sınırlı değil. Yazılacak daha fazla detay var. Bu yazımda size basit bir şekilde asenkron programlamanın ardındaki fikri açıklamaya çalıştım. İnşallah faydalı olmuşumdur.

Kolay gelsin!

2 yorum: