Rehber C# ile Thread, Multi-Thread, Task ve BackgroundWorker kullanımı

Merhaba.

Genel olarak akşam ve gece saatlerinde müsait olduğum için rehberlerimi bu saatler içinde yapıyorum.

Bugün sizlere C# dili ile yazdığınız bir programın ne şekillerde çalıştırılabilceğini göstermeye çalışacağım.

Rehberimiz 4 ana maddeden oluşuyor;

  • Thread.
  • Multi-Thread (Paralel Programlama).
  • Task (TPL / Task Parallel Library).
  • BackgroundWorker.
Öncelikle tanımlarıyla başlayalım;

1676333582803.png


Thread nedir?

Thread
, çok sayıda işi tek bir kişiye yaptırmak yerine çok sayıda işi, çok sayıda kişiye yaptırmak olarak tanımlayabiliriz.

Teknik Tanımı: Bir process’in birden fazla işi aynı anda yapmasını sağlayan yapılara Thread denir. Bir process bünyesinde bir ya da birden fazla Thread barındırabilir.

Öncelike Thread bir program içerisinde değildir. İşletim sistemleri aynı anda birden çok işlemi yapmak için Thread adındaki teknolojiyi kullanır. İşletim sistemi, mikrosaniyeler içerisinde Thread sayesinde sürekli olarak iş değişimi yaptırır işlemciye.

Bir yazılım çalıştırıldığı zaman işletim sistemi o yazılıma sadece 1 adet Thread verir. Bu Thread'e Main Thread adını veriyoruz. Main Thread, programın çalıştığı süre boyunca çalışır. Bilgisayar programları kodları sırayla işler ve çalıştırır. Main Thread'e birden fazla iş vermeye çalıştığınız zaman bir işlemi bitirmeden diğer işleme geçmez. Arayüzlü bir yazılım yazıyorsanız işlem biteseye kadar arayüzün dondoğunu fark edersiniz. Bunun nedeni Main Thread'in başka bir iş yaparken aynı anda birden fazla iş yapamasından kaynaklanıyor.

Şimdi gelelim Thread'in kullanımına;

Normalde işletim sistemi Main Thread'i direkt program çalıştığı anda çalıştırır. Siz sonradan ekstra Thread ekleyebilirsiniz.

Küçük bir Form oluşturdum. İçerisine bir Void tanımladım. Butona basıldığı zaman Listbox'a sayıları eklemeye başlıyor.

1676333784498.png


Kodlarımız bu şekilde;

Buton kodu;

C#:
Thread launch = new Thread(add_number);
launch.Start();

Void kodu;
C#:
private void add_number(){
    for (int i = 0; i<= 50; i++){
        listBox1.Items.Add($"Sayı: {i}");
        Thread.Sleep(1000 - DateTime.Now.Millisecond); // 1 saniye bekleyerek çalıştırıyor döngüyü.
    }
}

Programı çalıştırdığınız anda şöyle bir hata alabilirsiniz;

1676333893978.png


Bunun nedeni, kullandığımız Thread'in başka bir işlem tarafından kullanılmasından kaynaklanır.

Bu hatayı çözmenin en kolay ve basit yöntemi ise Thread'i başlatmadan önce şu kodu üst kısmına girmemiz yeterli;

C#:
Control.CheckForIllegalCrossThreadCalls = false;

Bu kod başka iş parçacığı tarafından kullanılan işlemlerde hata vermeyi önler.

1676333994785.png


Gördüğünüz üzere program 1 saniye aralıklarla ListBox'a veri ekliyor. Bu işlemi yaparken form kasmadan rahat bir şekilde kullabiliyoruz.

Thread hakkında detaylı bilgi almak için: Thread Sınıf (System.Threading)

Şimdi geçelim diğer maddeye.

1676335075370.png


Multi-Thread (Paralel Programlama) nedir?

Bilgisayar mimarisinde, MultiThreading (çok iş parçacıklı), bir merkezi işlem biriminin (CPU) (veya çok çekirdekli bir işlemcideki tek bir çekirdeğin) aynı anda işletim sistemi tarafından desteklenen birden çok yürütme iş parçacığı sağlama yeteneğidir. Bu az önceki örneklerde gösterdiğimiz üzere aynı anda birden çok işlem yapma biçimine deniyor.

Şidmi aynı örnek üzerinden devam edelim.

Form'a 2 adet Listbox daha ekledim. 3 adet Listbox'a aynı anda değerler ekletelim.


1676334213294.png


Şimdi aynı buton üzerinden 3 adet Thread başlatalım;
C#:
Control.CheckForIllegalCrossThreadCalls = false;

Thread launch1 = new Thread(add_number1);
launch1.Start();

Thread launch2 = new Thread(add_number2);
launch2.Start();

Thread launch3 = new Thread(add_number3);
launch3.Start();

Void'lerimiz bu şekilde;
C#:
        private void add_number1()
        {
            for (int i = 0; i<= 50; i++)
            {
                listBox1.Items.Add($"Sayı: {i}");
                Thread.Sleep(1000 - DateTime.Now.Millisecond); // 1 saniye bekleyerek çalıştırıyor döngüyü.
            }
        }

        private void add_number2()
        {
            for (int i = 50; i <= 100; i++)
            {
                listBox2.Items.Add($"Sayı: {i}");
                Thread.Sleep(1000 - DateTime.Now.Millisecond); // 1 saniye bekleyerek çalıştırıyor döngüyü.
            }
        }

        private void add_number3()
        {
            for (int i = 100; i <= 150; i++)
            {
                listBox3.Items.Add($"Sayı: {i}");
                Thread.Sleep(1000 - DateTime.Now.Millisecond); // 1 saniye bekleyerek çalıştırıyor döngüyü.
            }
        }

1676334376803.png


Gördüğünüz üzere her Listbox'a aynı anda veri ekliyor ve program donmadan haraket etmeye devam ediyor. Bu yapıya Multi-Threading (paralel programlama) diyoruz.

Bu sayede dinamik işlemler ve programı kapatıp açmadan farklı işlemleri aynı anda yapabilirsiniz.

Multi-Threading hakkında detaylı bilgi almak için:
Parallel Programming in .NET: A guide to the documentation

Şimdi geçelim diğer maddeye.

1676335208277.png


Task (TPL / Task Parallel Library) nedir?

TPL
'nin amacı, uygulamalara paralellik ve eşzamanlılık ekleme işlemini kolaylaştırarak geliştiricilerin daha üretken olmasını sağlamaktır. TPL, kullanılabilir tüm işlemcileri en verimli şekilde kullanmak için eşzamanlılık derecesini dinamik olarak ölçeklendirir.

Intel bir işlemci kullanıyorsanız eğer Intel'in teknolojisi olan Hyper-V'den faydalanabilirsiniz. Hyper-V ile çok daha verimli çalışıyor Task.

Şimdi Task ile Thread'in farklarına bakalım;

  • Thread sınıfı, Windows'ta bir iş parçacığı oluşturmak ve işlemek için kullanılır.
  • Task, zaman uyumsuz bir işlemi temsil eder ve Task'ları zaman uyumsuz ve paralel olarak çalıştırmak için kullanılan bir API kümesi olan Görev Paralel Kitaplığı'nın bir parçasıdır.
  • Task bir sonuç döndürebilir. Bir iş parçacığından gelen sonucu döndürmek için doğrudan bir mekanizma yoktur.
  • Task, iptal belirteçlerinin kullanımıyla iptali destekler. Ancak Thread bunu yapmaz.
  • Bir Task'ın aynı anda gerçekleşen birden fazla işlemi olabilir. İş parçacıklarının aynı anda yalnızca bir görevi çalışabilir.
  • Asenkron (async) ve (await) anahtar kelimelerini kullanarak kolayca uygulayabiliriz.
  • Yeni bir Thread(), İş parçacığı havuzu iş parçacığıyla ilgilenmezken, Task, iş parçacığı havuzu iş parçacığı kullanır.
  • Task, İş Parçacığı'ndan daha üst düzey bir kavramdır.
Şimdi Task'ın kullanımına bakalım.

Task yapısal olarak kodlaması Thread ile neredeyse aynıdır.

Formumuz yine aynı.

Buton kodlarımız;

C#:
Control.CheckForIllegalCrossThreadCalls = false;

Task launch1 = new Task(add_number1);
launch1.Start();

Task launch2 = new Task(add_number2);
launch2.Start();

Task launch3 = new Task(add_number3);
launch3.Start();

Void kodlarımız;
C#:
         private void add_number1()
        {
            for (int i = 0; i<= 50; i++)
            {
                listBox1.Items.Add($"Sayı: {i}");
                Thread.Sleep(1000 - DateTime.Now.Millisecond); // 1 saniye bekleyerek çalıştırıyor döngüyü.
            }
        }

        private void add_number2()
        {
            for (int i = 50; i <= 100; i++)
            {
                listBox2.Items.Add($"Sayı: {i}");
                Thread.Sleep(1000 - DateTime.Now.Millisecond); // 1 saniye bekleyerek çalıştırıyor döngüyü.
            }
        }

        private void add_number3()
        {
            for (int i = 100; i <= 150; i++)
            {
                listBox3.Items.Add($"Sayı: {i}");
                Thread.Sleep(1000 - DateTime.Now.Millisecond); // 1 saniye bekleyerek çalıştırıyor döngüyü.
            }
        }

Gördüğünüz üzere yine aynı şekilde çalışır. Ancak bir farklılık vardır. Thread bir işlemcinin tek çekirdeğini kullanırken, Task bir işlemcinin Task sayısı kadar farklı işlemci çekirdeklerine bölerek çalıştırır. Bu sayede maksimum performans alınır.

O yüzden gerekmedikçe Thread kullanmayın. Çünkü Thread, Windows tarafından güvensiz olarak işaretlenebiliyor. Bu da güvenli kod yazmanın önüne geçiyor.

Task (TPL / Task Parallel Library) hakkında detaylı bilgi almak için:
Task Sınıf (System.Threading.Tasks)

Şimdi geçelim son maddemize;

1676336410502.png


BackgroundWorker nedir?

BackgroundWorker
, arka planda eş zamanlı çalışan işlemlerin yapılması için kullanılır. C#'da yazdığımız programlar çalıştırıldığında varsayılan olarak tek bir Thread üzerinden çalışır. Böyle bir durumda, bir işlemin başlatılabilmesi için öncelikle o an çalışmakta olan işlemin tamamlanması gerekir. Örneğin bir uygulama, kendini güncellerken güncelleme backgroundworker (ayrı bir Thread) kullanılarak yapılıyorsa , güncelleme işlemi esnasında kullanıcı uygulamayı kullanmaya devam eder. Aksi halde güncelleme işlemi bitene kadar kullanıcı uygulamayı kullanamaz ve uygulama kilitlenir.

Yapı yukarıda anlattığımız şekilde.

BackgroundWorker içerisinde aslında Thread çalıştırmaktadır. Arka plan işlemleri için en yaygın olarak kullanılan teknojilerden birisidir. Özellikle güncelleme işlemleri için oldukça popülerdir.

Şimdi kullanımına geçelim.

Bunun için Araç Kutumuzdan bir adet BackgroundWorker eklememiz gerekiyor.


1676335469022.png


Ardından özellikler paneline 3 adet Event gelir.

1676335495419.png

  • DoWork: İşlemleri yaptığımız kodları yazdığımız alan.
  • ProgressChanged: Bir işlem sürerken dinamik olarak bir alanda göstermemizi sağlayan özellik.
  • RunWorkerCompleted: Arka plan işlemi tamamlandığında, iptal edildiğinde veya bir özel durum oluştuğunda gerçekleşir.
İlgili alanlara çift tıklıyoruz.

1676335708358.png


Gördüğünüz üzere kodlarımız oluştu.

Şimdi bir işlem yaptıralım.

İşlem yapmadan önce ekranda işlemi göstermek için WorkerReportsProgress durumunu True yapmamız gerekiyor.


1676336089219.png


Form'umuzun tasarımı bu şekilde;
1676336150827.png


  • 1 adet BackgroundWorker.
  • 1 adet Listbox.
  • 1 adet Label.
  • 1 adet ProgressBar.
  • 1 adet Button.

Şimdi buton kodlarımızı yazalım;
C#:
Control.CheckForIllegalCrossThreadCalls = false;
backgroundWorker1.RunWorkerAsync();

Not: RunWorkerAsync() metodu Eş zamansız olarak çalıştırmamızı, yani BackgroundWorker'ı çalıştırmamızı sağlar.

Tüm BackgroundWorker Event kodlarımız;

C#:
         private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e){
            for (int i = 0; i <= 100; i++){
                listBox1.Items.Add(i);
                backgroundWorker1.ReportProgress(i); // Progress işleminin % kaçta olduğunu raporlar.
                Thread.Sleep(250); // 250 milisaniye de bir çalışacak şekilde ayarlandı.
            }
        }
        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage; // ProgressBar'ı dolduruyor.
            label1.Text = "%" + e.ProgressPercentage.ToString(); // Label'e % kaç olduğunu yazdırıyor.
        }
        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){
            MessageBox.Show("İşlem tamamlandı."); // "İşlem tamamlandı" diye ekranda işlem tamanlandığında gözüküyor.
        }

Gördüğünüz üzere dinamik bir şekilde, Form donmadan çalışıyor.

1676337973969.png


Son olarak işlem bitince "İşlem Tamamlandı" yazıyor.

1676338025566.png


BackgroundWorker hakkında detaylı bilgi için: BackgroundWorker Sınıf (System.ComponentModel)

Sonuç olarak günün sonunda hepsi aynı yere çıkıyor. Sadece gittikleri yollar ve çalışma prensipleri farklı.
Burada yer alan metodlardan herhangi birini kullanarak örneğin; 1 dakika süren bir işlemi 10 saniyeye kadar düşürebilirsiniz.

Buraya kadar okuduysanız teşekkür ederim :)

Kolay gelsin, iyi çalışmalar :like:


@TheAny @bbb1 @Börtü Böcük işinize yarayabilir.
 
Son düzenleme:
Olağanüstü mükemmel süper ötesi bir rehber. Kesinlikle bana göre Technopat için yeni bir YouTube sayfası açılmalı senin gibi birini oraya koymalı ve video çektirmeli Türkiye'de yazılım olarak kaynakların neredeyse hepsi İngilizce veya aşırı yüzeysel anlatılıyor bu yüzden böyle rehberlerin yaygın hale getirilmesi gerekiyor bence Technopat'ı bir Stack Overflow haline getirmeliyiz.
 
Olağanüstü mükemmel süper ötesi bir rehber. Kesinlikle bana göre Technopat için yeni bir YouTube sayfası açılmalı senin gibi birini oraya koymalı ve video çektirmeli Türkiye'de yazılım olarak kaynakların neredeyse hepsi İngilizce veya aşırı yüzeysel anlatılıyor bu yüzden böyle rehberlerin yaygın hale getirilmesi gerekiyor bence Technopat'ı bir Stack Overflow haline getirmeliyiz.

Tonlarca rehberim var, bu onların yanında hiçbir şey :)

Bazıları;

 

Yeni konular

Geri
Yukarı