Asenkron Ve Paralel Programlamada Lock Mekanizması

Selamlar Arkadaşlar,

Bu makalede Mvc bir sayfaya ait, farklı tipte modelleri asenkron ve paralel çekerken (Lock) mekanizmasının nasıl yapılacağını ve yanlış kullanımda ne gibi sonuçlar doğrucağını hep beraber inceleyeceğiz. Aynı zamanda Try{} Catch{} mekanizmasının MultiTasking bir yapıda nasıl yönetilceğini, yine örnekler ile inceleyeceğiz.

Öncelikle “Lock” işlemi örneğin bir cache düştüğü zaman birden fazla kişinin, cache’in düşmesi anında DB’ye, ya da ne işlem yapılmak isteniyor ise ona sadece 1 kişi tarafından ulaşılmasını sağlıyan bir güvenlik mekanizmasıdır. Aslında static object’den başka birşey değildir. Ama işlevi açısından hayati bir önem taşır. Yüksek trafikli bir sitede “lock“‘ın düzgün kullanılmaması durumunda, belirlenen süredeki cache düştüğü zaman, aynı anda DB’ye 1 milyon kişi gidebilir. Bu da tüm sistemin down olmasına sebebiyet verir.

Singleton_Lazy_Sync

Yukarıda görülen yönteme Double Check Lock denir. İlgili nesnenin “null” olup olmadı kontrol edilip, locklanır. Ve tekrardan kontrol edilip ilgili işlemler yapılır. Yani ilgili nesne 2 kere kontrol edilmiş olunur.

Durum 1:

Şimdi de biraz da Task Async yapısından bahsedelim. Bunla ilgili detaylı bilgili önceki makalemden erişebilirsiniz.Aşağıdaki örnekde 3 farklı durum “DoMultipleAsync()” methodu içerisinde çalıştırılmıştır. Amaç 3 farklı işi asenkron ve paralel olarak çalıştırmak ve olabilecek en kısa sürede bitirmektir. Aşağıdaki örnek, bir console uygulamasıdır. Aslında birtane “ExcAsync()” adında asenkron Task bir method vardır. İlgili method içinde 1 den 10’a kadar asenkron olarak console’a gönderilen string değer, yanında sıra numarası ile yazdırılmaktadır. İlgili method 3 kere çağrılmıştır. Yani 3 farklı Task’e atanmıştır. Bu 3 farklı işlemin asenkron olarak çalıştığının anlaşılması için “Task.Delay(100)” methodu ile “0.1 sn” bekletilmiştir. Böylece bekleme anında farklı taskların nasıl çağrıldığı incelene bilecektir.

Try {} Catch{} işleminde tüm Tasklar göz önüne alınmıştır. Yani hatalar tüm Task işlemleri “await allTasks“‘ın ardından toplu olarak bakılmaktadır.Tüm işlemler bittikten sonra “WhenAll” ile atandıkları “allTasks”‘ın içinde gezilerek tüm tasklara ait hatalar ekrana yazdırılır. Aşağıdaki örnekde “theTask1″ yani gönderilen info içinde,”First” kelimesi geçen task için özellikle Exeption fırlatılmıştır. Amaç tüm işlem bittikten sonra ilgili hata mesajını görebilmektir. Yani 3 Taskden 1’inde oluşan hata diğerlerini etkilememekte ve diğer 2 Task işlemlerini bitirebilmektedir.

Untitled

Yukarıdaki çıktıya dikkat ederseniz, her bir “0.1” sn bekleme anında farklı bir task çağrılmış ve paralel işleyiş’e güzel bir örnek verilmiştir.

Async Lock Object : Yukarıda görülen asenkron methodları normal static object bir Lock nesnesi ile Locklanamaz. Bunun için aşağıda görülen “SemaphoreSlim” sınıfının kullanıldığı, AsyncLock objesi üreten bir sınıf kullanılır. İçinde tanımlanan “LockAsync()” methodu ile her bir Task’a özel yeni bir Lock nesnesi önceden oluşturulur ve “ExcAsync()” methodunda her bir task’a özel olarak gönderilir. Dikkat ederseniz her bir task’a ait farklı lock objeleri kullanılmıştır. Eğer hepsi için tek bir “Lock” objesi kullanılır ise, paralel bir işleyişden söz etmek mümkün olmaz. Ve tüm taskler birbirlerini beklemek zorunda kalırlar.

Yukarıdaki örnek çıktıda da görüldüğü gibi, her bir for döngüsü içinde “delay(100)” konulduğu için her bekleme anında farklı bir task çalıştırılmıştır. Bu nedenle farklı taskler random bir sıra içinde sıralanarak ekrana yazdırılmaktadır. En sonda da hata fırlatılan “First Task” console yazdırılmıştır.

Durum 2: Aşağıdaki örnekde yeni bir Task(Task22) daha eklenmiştir. Ama burada farklı olarak Task2’de kullanılan ==> “Second” Lock object’i [m_lock2] “Task22″‘de ==> “Second2” kullanılan Lock object [m_lock2]’in aynısıdır. Bu demek oluyor ki “Task2”, “Task22″‘nin bitmesini beklemektedir. Bu durumda paralel ve asenkron bir çalışma “Task2” için söylenememektedir. Aşağıdaki çıktıdan da anlaşılacağı gibi “Second2” taskinin bitmesi beklenmiş ve “Second” Taskinin en sonunda senkron olarak çalıştırılması sağlanmıştır..

Bu durumda Lock objelerine dikkat edilmeli ve her bir task için ayrı bir lock object’i üretilmelidir. Aksi takdirde asenkron ve paralel bir çalışma yapılması sözkonusu değildir.

Untitled2

Durum 3: Peki diyelim ki yapılcak işlem sürekli değişen dinamik bir yapı olsun. Örneğin bir haberin detay sayfasına gidilecek. Bu durumda haber detay sayfası tek de olsa, okunacak haber dinamiktir. Yani her zaman değişebilir. Eğer hepsi için aynı “Lock” object kullanılır ise, bir haber cache den düştüğü zaman, ilgili data DB’den çekilmek istendiğinde, diğer tüm haberler onu beklemek zorunda kalacaktır. Bu da inanılmaz bir performance kaybına neden olacaktır. İşte tam bu sorunda ilk akla gelen her bir detay için ayrı Lock object’i üretmektir. Aşağıdaki son revizyonda yeni bir “Dictionary” nesnesi üretilmiş, ve oluşturulan her yeni Lock object’i bu dictionar içine konmuştur. Bir daha yeni bir habere gelindiğinde öncelikle, ilgili lock object bu listede aranmış ve yok ise yeni yaratılıp bu listeye konmuştur. Her bir lock object’e karşılık gelen haber detayın key’i tabii ki ilgili haberID’si olan “contentParentID”‘dir.

Ayrıca ilgili dictionary nesnesinin zamanla şişmemesi için, çarşamba günleri gece 1’den sonra temizlenmektedir. Böylece her bir haber detay için yani, her bir dinamic durum için yeni bir lock object yaratılmış ve ilgili dictionary’e atılmıştır. Böylece haber detaylardan herhangi biri, cacheden düştüğü zaman sadece ilgili haber kitlenmekte ve diğer haberlerin DB’den çekilmesi engellenmemektedir.

Aşağıdaki örneğe dikkat edilir ise şeytan ayrıntılarda gizlidir:) Aynı zamanda ilgili Dictionary nesnesine de olmayan bir Lock nesnesi yine “lockDic” adında yeni bir static lock object’i ile kitlenip atılmaktadır.

Program.cs:

Böylece geldik bir makalenin daha sonuna. Bu makalede asenkron yapılarda Lock nesnesinin nasıl kullanılacağına ve yanlış kullanımında ne gibi sakıncaların olabileceğine hepberaber inceledik. Unutulmamalıdır ki dinamic içerikli yapılarda lock object’in her bir detay için farklılaştırılması bize, asenkron paralel yapının korunmasını sağlamaktadır.

Yeni bir makalede görüşmek üzere hoşçakalın.

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

2 Cevaplar

  1. Yunus KIRAN dedi ki:

    ThreadSafe bir işlemde double check yerine Lazy class’ ı kullanıyoruz hocam. Fakat bazı yerlerde thread yönetiminde de kullanıldığına şahit oldum. Multithread uygulamalarda hala try catch yönetimi çok zor iç içe olan threadlerde örneğin.

    • borsoft dedi ki:

      Selamlar,
      Aslında thread ile task gerçekten karıştırıl ise de aslında birbirinden farklı konular. Lazy load ile lock işlemini, pek degil hiç önermiyorum.

      Bir de bu makalede zaten iç içe threadlerden uzak durulmuş, paralel multitask çalışan işlemler üzerinden örnekler verilmiştir.

      İyi çalışmalar.

Bir Cevap Yazın

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