C# Asenkron Mimarisi

Bu yazımda C#’ta Asenkron mimarisini inceleyeceğiz.Bir program akışında bir işlem bitmeden başka bir işlem yapılmaz.Asenkron mimari bize, süreçlerin birbirinden bağımsız aynı anda çalışmasını sunuyor.C#’ta Asenkron mimarisini uygulamak için iki yapı mevcuttur.Bunlardan biri Asenkron Metodlar (BeginInvoke, Stream.BeginRead vb..) diğeri Thread Sınıfıdır.Bu yazımda sizlere Asenkron metodları göstereceğim.
Öncelikle mevzuyu daha derinlemesine açıklamak istiyorum.Aşağıdaki kodları inceleyiniz.

            while (true)
            {

            }
            MessageBox.Show("Test");

Yukarıdaki işlem Senkron çalıştığı için sonsuz döngü bitmediği taktirde “Test” mesajını görmemiz mümkün olmayacaktır.Sonsuz döngüyü ve “Text” mesajını Asenkron çalıştırdığımız taktirde ikiside aynı anda çalışabilir hale gelecektir.Yani birbirlerinden bağımsız çalışacaklardır.
Değişik komut bloklarını aynı anda asenkron çalıştırmak için delegelere başvururuz.


Şimdi aşağıdaki kodları inceleyiniz.

        void X()
        {
            while (DateTime.Now.Second != 20)
            {
                this.Text = DateTime.Now.Second.ToString();
            }
        }
        private void button1_Click(object sender, EventArgs e)
        {
            X();
        }

buton1 isimli nesneye tıkladığımız zaman X metodu devreye girecektir.Formun Text’inde saniyeleri göreceğiz ama formu hareket ettiremeyeceğiz,kapatamayacağız ya da başka bir işlem yapamayacağız.Çünkü bu yapılmaya çalışılan işlemlerin hepsi(sürükleme,kapatma vs),sonuçta programımızın while döngüsü bitmeden gerçekleştirilemeyecektir.Bunun sebebi yukarıda X medotu içindeki while döngüsü senkron çalışmaktadır ve kendisinin çalışması bitmeden,başka işleme izin vermiyor.
Şimdi Asenkron mimariyi kullanma zamanı.X metodunu asenkron olarak çalıştıralım.
Yukarıdaki kodlara bir + olarak delegate koduda ekleyip aşağıda yayınlıyorum.

        delegate void AsenkronHandler();
        void X()
        {
            while (DateTime.Now.Second != 20)
            {
                this.Text = DateTime.Now.Second.ToString();
            }
        }
        private void button1_Click(object sender, EventArgs e)
        {
            X();
        }

Şimdi bu delegemizden bir nesne oluşturup,X metodumuzu bu delegeye işaret ettirelim.

            AsenkronHandler asenkron = new AsenkronHandler(X);
            asenkron(); //Böyle çalıştırırsam da senkron çalışır.
            asenkron.Invoke(); //Böyle çalıştırırsam da senkron çalışacaktır.

Yukarıda gördüğünüz gibi bir tek delegeyle metodu çalıştırmak Asenkron çalıştırmaya yetmiyor.Peki ne yapmamız lazım.
AsenkronHandler adında delegate nesnesinin “Begin” ile başlayan metodları, asenkron çalıştırma yapabilmek içindir.

BeginInvoke() Metodu :
BeginInvoke() metodu ile, delegemizin işaret ettiği metodu asenkron çalıştırmış oluyoruz.Burada BeginInvoke() metodu bizden AsyncCallback delegesi aracılığıyla çalıştırılacak bir metod istiyor.Bunu istemesinin sebebi şudur ;
Delegemizin çalıştırdığı metodun işi bittiğinde biz programcı olarak o işin bittiğinden haberdar olmak isteyebiliriz.Burada AsyncCallback delegesinin çalıştıracağı metod,delegemizin çalıştıracağı metodun işi bittiği zaman devreye girer(Otomatik olarak).
BeginInvoke() metodu bizden 2. olarak object bir değer ister.Bizim buna vereceğimiz değer AsyncCallback delegesinin çalıştırdığı metodun IAsyncResult tipinden tanımlanmış parametresine gönderilir.

Şimdi yukarıda anlattıklarımı kodlarda görelim.

       private void button1_Click(object sender, EventArgs e)
        {
            AsenkronHandler asenkron = new AsenkronHandler(X);
            asenkron.BeginInvoke(new AsyncCallback(Y), this);
/*BeginInvoke metodu 1. parametresinde, AsyncCallback delegesinden, geriye dönüş
tipi olmayan ve IAsyncResult tipinden parametre alan bir metod istiyor.
IAsyncResult tipinden parametre alan Y() metodunu yazıp ben BeginInvoke
metodunun 1. parametresine gördüğünüz gibi yazıyorum.2. parametresine ise,
this(yani bu formu) gönderiyorum.Buraya gönderilen object değer,Y metodunun
IAsyncResult tipinden olan dd adlı parametresine gönderilecektir.
*/
        }
        void Y(IAsyncResult dd)
        {
/*Bu metoddaki IAsyncResult tipinden dd parametresine gelen değer,
AsyncState özelliğinden elde edilebilir.*/
        }

Şimdi programımızı derleyip çalıştırırsak eğer,buton1’e tıkladığımızda aşağıdaki hatayla karşılacağız 🙂
“Cross-thread operation not valid: Control ‘Form1’ accessed from a thread other than the thread it was created on.”
Bu hata,threadlardan oluşuyor.Threadler çakışıyor.
Formun loadına, ya da button1 in Click özelliğinin ilk satırına şu kodu yazarsanız hata vermeyecektir.

CheckForIllegalCrossThreadCalls = false;
/*"Cross-thread operation not valid: Control 'Form1'
 accessed from a thread other than the thread it was created on."
hatası vermemesi için yazılır.Threadlerin çakışmasını engeller.*/

Son olarak programımızı derleyip çalıştırdıktan sonra, formumuzun Text’inde saniyeleri görürken, formumuzda başka işlemler yapabileceğiz(kapat,büyüt,küçüt,taşı vs.).Artık X metodundaki while döngüsü Senkron değil Asenkron çalışmaktadır.Asenkron while döngüsü bitmeden , ondan bağımsız diğer işlemlerimizide gerçekleştirebiliyoruz.

İşte bu şekilde Asenkron çalışıp, aynı anda birden fazla işlem yapabilirsiniz..

Bir sonraki yazımda görüşmek üzere..
İyi çalışmalar.

Bunlar da hoşunuza gidebilir...

14 Cevaplar

  1. Bilgehan Çırak dedi ki:

    Yeni başlayanlar için çok açıklayıcı bi yazı olmuş. Devamının gelmesini temenni ederim

  2. Bilgehan ÇIRAK dedi ki:

    Öncelikle uzun süre sonra açtığım c# da tekrar aynı yazıyı okuyup tekrardan beğenmek şuan için güzel bir duygu. Yazınız için teşekkür eder takıldığım bir noktayı aktarmak isterim. Yukarıda form1 e yazdırdığımız texti bir labela yazdırmak istediğimizde ne yazıkki aynı sonucu alamadım. Bunu nasıl çözebilirim bir fikriniz var mıdır?

    • Gençay dedi ki:

      Bak çocuk, web alanına yazdığın pornografik siteden dolayı senin gibilerin soracağı her zaman soru olur ama alacağı cevap ebediyen olmaz.

  3. Ali dedi ki:

    Hocam, öncelikle teşekkürler yazınız için. Aynı işlemi wpf-də yapmak istiyorum. Fakat bağlantı kurub, bağlantıdan aldığım değeri penceredeki herhangi textboxa ya da label’a ekleyemiyorum. İşlemler farklı thread’lerde olduğu için. Ne yapa bilirim?

  4. Umut Sun dedi ki:

    Elinize sağlık çok güzel bir anlatım datagridview’e 50.000 kayıtlı bir datatable’ı aktarırken programı dondurmayan başka bir yol bulamamıştım kendi kullandığım invoke yöntemi olmamaktaydı bu delegate mantığını sizden öğrenerek uyguladım çalıştı çok teşekkür ederim tekrar

  5. Murat dedi ki:

    Yaptığın iş gerçekten çok güzel bir iş, Fazlasıyla saygı duyuyorum, Yani türkçe kaynak üretmenize saygı duyuyorum. Bu konuda gerçekten çok fazla eksikliğimiz var. Herkesin inigilizce bilmesi veya belkide bu işe çok küçük yaşta merak salmış kardeşlerimiz içinde çok iyi amma ve lakin bütün türkçe kaynaklarda Cross-Thread problem’ın çözümü olarak hata mesajlarını engellemek yazılmış. Bu bir çözüm kesinlikle değildir. Sadece ileriki aşamalarıda debug edebilmek için o anlık görmezden gelmek içindir. Bunların farklı çözüm yöntemlerinide yazınıza eklerseniz tadından yenmez. Yinede iyi iş

    • Gençay dedi ki:

      Öncelikle ferasetiniz için teşekkürlerimi sunarım.
      İlgili hususta sonuna kadar haklı olduğunuzu bildiririm.
      Lakin makalede asenkron mimari mantığı üzerine odaklanıldığından dolayı ilgili detayla konu teferruatlandırılmamıştır. İlk fırsatta değindiğiniz detayı ilgili makale adresi refere edilerek gerçekçi çözümlerle değerlendirilecektir.

      Teşekkürler. Sevgiler.

  1. 17 Haziran 2016

    […] mimari dendiği vakit benim aklıma Delegate(Delege) yapıları ve BeginInvoke metodları gelmektedir. Bunların dışında Asenkron işlemler için bir […]

Bir cevap yazın

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

*

Copy Protected by Chetan's WP-Copyprotect.