MVC EntityFramework Asenkron Programlama

Selamlar;

Bugün Mvc’de asenkron ve multi thread işlemler üzerine konuşacağız.

Diyelimki bir cafe’de kasada çalışan bir görevli olsun. Müşteriden tost siparişi geldi. Tost makinaya kondu ve bekleniyor. Bu bekleme zamanında eğer görevli yeni sipariş almaz ise yani işlemi bekler ise sıra dolar taşar.Yoğunluk çok artar. Doğru olan görevlinin tost olana kadar sipariş almaya devam etmesi ve tost bitince makinadan bir uyarı ile görevlinin sipariş alma işlemine ara verip tostu müşteriye vermesi ve kaldığı işe devam etmesidir. İşte asenkron programlama tam bu mantık üzerine çalışmaktadır. Bir request geldiği zaman thread pool’daki işlemci bu istek ile ilgilenmeye başlar.Mesela bir websitesinin string olarak download edilmesi istensin. Eğer işlem uzun sürecek ise bu esnada thread pool’daki thread gelen yeni request’e cevap verecektir. Download işlemi bitince process’den bir çağrı gelir ve thread önceki requestdeki işlemine kaldığı yerden devam eder. Mesela indirilen websitesindeki tüm linkleri alıp ön tarafta listelemesi gibi.

async2  Untitled

Aşağıda görüldüğü gibi üç çeşit async programlama modeli vardır.Biz tabi bu makalede Task-based asynch modeli üzerine konuşacağız.

taskbase

Örnek amaçlı günlük kurları alan aşağıda görüldüğü gbi asenkron  bir uygulama yazalım.

Öncelikle yukarıda methodun başında async Task kullanılmıştır.Burada methodun asenkron olduğu ve birtane task tipinde dönüş yapılacağı,sonucun da string içerdiği belirtilmiştir.

Ayrıca WebClient’ın DownloadStringTaskAsync şeklinde asenkron çalışan bir method’u vardır. Başına’da await kelimesi konmuştur. WebClient’dan bir request’de bulunulduğunda, işlem bitene kadar alt satıra inmeden beklenmesini await kelimesi ile belirtilir. İşlem yapılırken WebClient’ın string’i download etmesi kısmını bu düzenden ayırıp kendi başına çalışmasını sağlayan işlem bitince de geribildirimde bulunun kısım methodun başına konan async ifadesidir. Bu sayede işlem yoğunluğundan dolayı herhangi bir blocklanma olmamaktadır. Method dönüş tipi olarak Task döndürmektedir.

xNRrO

Şimdi de database’den ürünleri async olarak çekelim. Bu sayede çekilen datanın fazalalığından veya connection ile ilgili sürenin uzamasından dolayı herhangi bir blocklanma ile karşılaşılmaz.

Aşağıda görüldüğü gibi ToListAsync ile linq’in async özelliğinden faydalanılmıştır. Entity 6.0 ve üzeri linq’de async desteklemektedir. Product tablosundan async olarak data çekilmekte gene await ile işlemin bitmesi beklenmekte ve method başına konan async Task ile işlemin asenkron  olarak yapılması ve dönüş tipinin Task olduğu belirtilmiştir. Sonuç List<tblProduct> içermektedir.

entity

Bir de Log tablosundan dataları async olarak aşağıda görüldüğü gibi çekelim.

Şimdi HomeController’ımızda Index methodumuz’da  yukarıda belirtilen 3 farklı datayı çekip View Modelimizi dolduralım. İlgili modelimiz aşağıda belirtilmiştir.

Şimdi de AsyncController’dan türeyen HomeController’ımızı oluşturalım.

Async

Aşağıda görüldüğü gibi async Tasck<ActionResult > döndüren bir Index Methodumuz vardır. Asenkron olarak Task tipinde ActionResult döndüren bir methoddur. Üç Task’ımıza request yapıldıktan sonra await Task.WhenAll methodu ile tüm taskların tamamlanması beklenir. Tüm tasklar bitince ilgili model doldurulup Index View model ile birlikte döndürülür. Bu belirtilen üç task paralel olarak çalışmaktadır. Ayrıca sistemi block’e etmeden asenkron olarak arkada sistemden bağımsız olarak kendilerinden istenen işleri yaparlar. Taskler tamamlandıkça bittiklerine dağir callback yaparlar. Tüm tasklar bittikten sonra await ile bekletilen kısım atlatılıp bir sonraki yani ilgili modelin doldurulması ve view’ın döndürülmesi işine geçilir.

Index View :

 Ekran Çıktısı:

screen

Yukarıda solda kurlar, ortada ürün dataları ve en sağda log datalarının bilgisi eş zamanlı çekilip ekran gösterilmesi sağlanmıştır. Toplam işlem süresi 5 sndir.Sisteme yük bindirdikçe yani anlık request binleri bulsa bile süre asenkron yükleme nedeni ile hem çok değişmeyecek hemde sistem bloke olmayacaktır.

Şimdi bir test yapalım.Uygulamamızı senkron olarak alttaki gibi yazalım:

Şimdi Apache Bench ile yani ab.exe ile load test yapıcaz. Apache sunucu testidir. Makinada IIS kurulu ise Apache kurmanıza gerek yoktur.

ab -n 100 -c 10 http://www.yahoo.com/

Kullanım şekli yukardaki gibidir -n 100 user sayısını -c 10 concurrency yani herbir user için request sayısını belirtmektedir. En sonda da load test yapılacak url belirlenir.

Aşağıda 500 user ve 100 concurrency ile yukarıdaki senkron  uygulama load test’e tabi tutuldu.9.981 sn toplam sürede en uzun request 7.563 sn sürdü.

regular

Aynı test asenkron uygulama için 500 user ve 100 concurrency ile aşağıdaki gibi çalıştırılmıştır.6.808 sn toplam sürede en uzun request 2.229 sn sürmüştür.

async2

Yukarıdaki load testde de görüldüğü gibi senkron ve asenkron uygulamalar arasındaki performans farkı yük artışı ile büyük değişiklik göstermektedir.

Geldik bir makalenin daha sonuna yeni bir makalede görüşmek üzere hoşçakalın.

Herkes Görsün:

Sevebilirsin...

7 Yanıt

  1. Enver Yasin Erdoğdu diyor ki:

    Çok güzel, açık, akıcı bir makale olmuş elinize sağlık. Başarılarınızın ve makalelerinizin devamını dilerim.
    İyi akşamlar.

  2. Gokhanax diyor ki:

    Güzel ve açıklayıcı bir yazı, emeğinize sağlık.

  3. Mustafa diyor ki:

    Öncelikle bu değerli yazı için teşekkür ederim ellerinize sağlık. Aklıma takılan bir soru var;

    Her metotu Task olarak tanımlamamız daha mı doğru olur? Ya da Task olarak kullanımı ne zaman tercih etmeliyiz?

    • borsoft diyor ki:

      Selam Mustafa;
      Öncelikle teşekkürler;
      Her method() kesinlikle her zaman Asenkron olarak TANIMLANMAZ! Eğer yapılacak iş uzun bir zaman alacak ve sistem gerçekten yoğun ise yani bu arada cevap vermesi gereken başka requestler var ise tabiki yeterli bir memory ve Cpu ile Task methodlar tercih edilebilir. Unutma ki her getirinin bir de götürüsü vardır!

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir