Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

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...

22 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.

  6. fatih dedi ki:

    Emeğinize sağlık hocam,benim bir sorum olacaktı birde.
    Benim elimde bir method var rest api çağırıyor bu method.Ben bu methodun en fazla 1 saniye çalışmasını istiyorum.Eğer 1 saniyeyi aşarsa da methodun çalışmasını durdurup o methoddan sonraki methodlara devam etmesini yani kaldığı yerden devam etmesini istiyorum.Nasıl bir yapı kurulabilir burada?

    Tşkkürler tekrardan….

  7. Ertuğrul dedi ki:

    Hocam merhaba;

    Çok açıklayıcı biryazı ama şu ISyncResult kodlarını analamadım…

    Async sınıfından bir nesne ürettik sonrası boş ama ezbere yaptım.

    Sadece ben delegeye 2 metod yüklediğimde temsilcinin tek hedefi olamalı uyarısı aldım …yani temsilci tek metod çalıştırabilyormuş … eklemek istedim …

    teşekkürler

    • Gençay dedi ki:

      Merhaba,

      Delegate’ler birden fazla metot çalıştırabilmektedir.

      Hangi durumda ilgili hatayı aldığınıza dair örnek paylaşır mısınız?
      Teşekkürler.

      • Ertuğrul dedi ki:

        hocam 1 program akışında 2 tane begininvoke kullanabilir miyiz?

        yani her biri bir metodu çalıştıracak ve bu sırada form kitlenmeyecek

        yani bir metod bir listboxa 1000000 a kadar yazdırırken diğer metod da listbox2 ye 1000000 e kadar yazdırıyor olacak o sırada biz formdaki diğer butonları kullanabileceğiz

    • Ertuğrul dedi ki:

      hocam denedim sanırım begininvoke sadece 1 tane ise çalıştırılabiliyor

  8. Ertuğrul dedi ki:
    public Form1()
            {
                InitializeComponent();
                CheckForIllegalCrossThreadCalls = false;
            }
            private void firstList()
            {
                for (int i = 0; i < 100000; i++)
                {
                    listBox1.Items.Add(i);
                }
    
            }
            private void secondList()
            {
    
                for (int i = 0; i < 100000; i++)
                {
                    listBox2.Items.Add(i);
                }
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                doubelWorkHandler worker = new doubelWorkHandler(firstList);
              
    
                AsyncCallback changeWay = new AsyncCallback(metod);
    
                worker.BeginInvoke(new AsyncCallback(metod), this) ;
    
       
            }
    
            void metod(IAsyncResult result)
            {
    
            }
    
            void metod1(IAsyncResult result1)
            {
    
            }
            
            private void button2_Click(object sender, EventArgs e)
            {
                doubelWorkHandler worker1 = new doubelWorkHandler(secondList);
    
    
                AsyncCallback changeWay1 = new AsyncCallback(metod1);
    
                worker1.BeginInvoke(new AsyncCallback(metod1), this);
            }
    

    hocam amacım 2 metodu asenkron çalıştırabilmek bu sırada form uygulaması ile etkileşimde olmaktı

  9. Ertuğrul dedi ki:

    sanırım karışık oldu

    bir delege oluşturdum

    2 de metot amacım bu 2 metodu asenkron çalıştırmak bu sırada form ilemlerini sıkıntı yani donma olmadan yapmak

    1 metodu asyncallback ile çalıştırırken formu kullanıyorum ama

    ikinci hazırladığım metodu asenk çalıştırmak isterken begininvoke yaptığımda form kitleniyor ve sadece 1 metod çalışıyor

  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 yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir