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.

Source: https://channel9.msdn.com/Events/TechDays/Techdays-2012-the-Netherlands/2287

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

18 Cevaplar

  1. Enver Yasin Erdoğdu dedi 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 dedi ki:

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

  3. Mustafa dedi 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 dedi 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!

  4. Ahmed dedi ki:

    Bora abi bir siteyi komple tüm içeriği web api den gelecek şekilde yazdığımızı düşünelim. Burada her veri çekecek action u asenkron mu yapmalıyız. Mesela kullanıcı ana sayfada hem ürünleri hem sepeti hemde menüyü görecek aynı anda 3 defa api den veri gelecek. Ayrıca api i de asenkron mu yazmalıyız

    • borsoft dedi ki:

      Bir WebApiden alıcaksan asenkron yerine tek bir model ile dönebilirsin. Yani Bir sınıfın var Container ve 3 propertysi var. Onlar da birer sınıf. Product,Basket and Menu şeklinde bir json geri dönüş yapabilirsin.ç Hatta servisi Cors’a açık yap ve Web’de client side’dan çekip doldur.

      İyi çalışmalar.

  5. sinan dedi ki:

    Burak Hocam elinize sağlık,
    Sorum şu olacak asenkron kullandığımız yerde controller AsyncController mı olacak her zaman?

    • borsoft dedi ki:

      Selam Sinan,
      İsim önemli değil. Zaten sitemden yazıyorsun :) Evet herzaman Async olmalı. Bunun en zor yanı, consol applicationlarda Main() methodu Async olarak işaretlenemez. Peki bu nasıl olacak. Araştır. Yolu var. İhtiyacın olur bulamassan sor gene:)

      iyi çalışmalar.

  6. sinan dedi ki:

    Burak yazdım kusura bakmayın o sırada burak arkadaşımla konuşuyordum :)

  7. Cihan dedi ki:

    Hocam aklıma bir şey takıldı.

    public async Task Test()
    {
    int userId = GetUserId();
    var products = await GetProducts(userId); //Database

    //OTHER
    //category vs..

    return Ok(“”);
    }

    böyle bir metotum var diyelim. Aynı thread da 2 istek bu metota geldi ( 2 farklı kullanıcı olarak 1 ve 2 id li). 1 idli kullanıcıda await kısmında beklemeye geçti ve 2 idli kullanıcı için bu metota geldi. Aklıma takılan bir istek başka bir isteğe müdale ediyor mu asenkron durumda yani kullanıcı 1’in isteğinde awaitten sonra userId kaç olacak yine 1 mi olacak yoksa 2 numaralı istekde oraya geldiği için 2 olarak mı gelecek. Biraz karmaşık oldu ama umarım anlatabilmişimdir.

    • borsoft dedi ki:

      Selam Cihan,

      userId hem 1 olucak hem 2 olucak. Hangisinin önce olucağı da belli değil :) 2 client farklı threadlerde çalışacaktır. Ben yerinde olsam bu tarz yapılarda senkron çalışırdım. Asenkron yapıları “push and forget” yani at ve unut yapılarda kullanırdım. Mesela bir video render edilmesi. Ya da bir webservices’den get işleminin yapılması gibi.

      İyi çalışmalar.

      • Cihan dedi ki:

        Cevabınız için teşekkür ederim. Peki neden senkron olarak yapmalıyım, tam olarak neden senkron olarak yapmamı öneriyorsunuz.

  8. Fatih BÜLBÜL dedi ki:

    Merhaba AsyncController farkı nedir kısaca anlatabilirmisiniz ?
    Teşekkürler,
    İyi çalışmalar.

  9. Ömer dedi ki:

    Hocam emeğinize sağlık çok açık bir anlatım olmuş.

sinan için bir cevap yazın Cevabı iptal et

E-posta hesabınız yayımlanmayacak.