BackgroundWorker vs arka plan Konu


166

Bir windows form uygulamasında kullanmanız gereken arka plan iş parçacığı uygulaması seçimi hakkında üslup bir sorum var. Şu anda BackgroundWorkersonsuz bir (while(true))döngü olan bir form var . Bu döngüde WaitHandle.WaitAnyilgi çekici bir şey olana kadar ipliği ertelemek için kullanıyorum . Beklediğim olay tutamaçlarından biri StopThreaddöngüden çıkabilmem için " " olayı. Bu olay geçersiz kılındığımda bildirilir Form.Dispose().

BackgroundWorkerGerçekten kullanıcı arayüzünü bağlamak istemediğiniz ve bir dosyayı indirmek veya bir dizi öğeyi işlemek gibi sınırlı bir sona sahip olmak istemediğiniz işlemler için tasarlanmış bir yerde okudum . Bu durumda "son" bilinmiyor ve sadece pencere kapatıldığında. Bu nedenle, BackgroundWorkerbu amaç yerine arka plan iş parçacığı kullanmam daha uygun olur mu?

Yanıtlar:


88

Sorunuzu anladığımdan, BackgroundWorkerstandart bir Konu olarak kullanıyorsunuz .

BackgroundWorkerUI iş parçacığını bağlamak istemediğiniz şeyler için önerilmesinin nedeni , Win Forms geliştirme yaparken bazı güzel olayları ortaya çıkarmasıdır.

Olaylar RunWorkerCompleted, iş parçacığının yapılması gerekenleri tamamladığını ve iş parçacığı ProgressChangedüzerindeki GUI'yi güncelleştirme olayını bildirmeyi sever .

Eğer Yani olmayan bu yararlanarak, ben yapmanız gereken ne için standart bir iş parçacığı kullanarak herhangi bir zarar görmüyorum.


emin olmadığım bir diğer konu, varsayalım üzerinde çalışan arka plan çalışan formu atmaya çalışıyorum. Kapanış sinyalini (ManualResetEvent) ve bundan bir süre sonra DoWork zarifçe çıkacaktır. Formun devam etmesine izin vermeli ve DoWork'un bitmesi biraz daha uzun sürebilir ya da iş parçacığının bir yolu var (ve daha iyi) olsa bile Atma. Gerçekten çıkana kadar arka plan çalışanına katılın ve ardından Dispose formun devam ediyor mu?
freddy smith

Sanırım BackgroundWorker.IsBusy orada aradığın şey.
ParmesanCodice

1
Sadece kullanın CancelAsync(ve CancellationPendingiş parçacığınızın kısa aralıklarla yoklanıp sorgulanmayacağını test edin, bunun yerine bir istisna oluşturmak istiyorsanız System.Threading.Thread.Abort(), iplik bloğunun içinde bir istisna oluşturan bir kullanın , durum için doğru modeli seçin.
Brett Ryan

369

Bazı düşüncelerim ...

  1. Arka planda çalışan ve kullanıcı arayüzüyle etkileşimde bulunması gereken tek bir göreviniz varsa BackgroundWorker'ı kullanın . UI iş parçacığına veri ve yöntem çağrılarını paylaşma görevi, olay tabanlı modeli aracılığıyla otomatik olarak ele alınır. BackgroundWorker'dan kaçının ...
    • derlemenizde doğrudan kullanıcı arayüzü yok veya bu arayüzle etkileşime girmiyor,
    • iş parçacığının ön plan iş parçacığı olması gerekir, veya
    • evre önceliğini değiştirmelisiniz.
  2. ThreadPool kullanınVerimlilik istendiğinde dişi . ThreadPool iş parçacığı oluşturma, başlatma ve durdurma ile ilgili ek yükü önlemeye yardımcı olur. Aşağıdaki durumlarda ThreadPool kullanmaktan kaçının ...
    • görev uygulamanızın ömrü boyunca çalışır,
    • iş parçacığının ön plan iş parçacığı olması gerekir,
    • iş parçacığı önceliğini değiştirmeniz veya
    • sabit bir kimliğe sahip olmak için iş parçacığına ihtiyacınız vardır (iptal, askıya alma, keşfetme).
  3. Uzun süren görevler için ve ör., Ön plan ve arka plan iş parçacıkları arasında seçim yapma, iş parçacığı önceliğini ayarlama, iş parçacığı yürütme üzerinde ayrıntılı denetim vb. Gibi resmi bir iş parçacığı modeli tarafından sunulan özelliklere ihtiyacınız olduğunda Thread sınıfını kullanın .

10
Arka plan işçisi System.dll derlemesinde ve System.ComponentModel ad alanındadır. Winform'lara bağımlılık yoktur.
Kugel

17
Bu doğrudur, ancak BackgroundWorkeriş parçacığının ilerlemesini, genellikle bir kullanıcı arayüzü içeren ilgili bir tarafa bildirmek üzere tasarlanmıştır. Sınıfın MSDN belgeleri bunu açıkça ortaya koymaktadır. Arka planda gerçekleştirilecek bir göreve ihtiyacınız varsa, bir ThreadPooliş parçacığı kullanmayı tercih edin .
Matt Davis

5
System.Windows.FormsMeclis hakkındaki görüşünüzle ilgili olarak ; BackgroundWorkerWPF uygulamaları için de yararlıdır ve bu uygulamaların WinForms'a referansları olmayabilir.
GiddyUpHorsey

12

Matt Davis'in söyledikleri hemen hemen aşağıdaki ek noktalarla:

Benim için ana farklılaştırıcı ile BackgroundWorkertamamlanan olayın otomatik olarak hizalanması SynchronizationContext. Bir UI bağlamında bu, tamamlanan olayın UI iş parçacığında tetiklendiği anlamına gelir ve bu nedenle UI'yi güncellemek için kullanılabilir. BackgroundWorkerBir UI bağlamında kullanıyorsanız bu önemli bir farklılaştırıcıdır .

Üzerinden gerçekleştirilen görevler ThreadPoolkolayca iptal edilemez (buna ThreadPool. QueueUserWorkItemVe delegeler asenkron olarak yürütülür). Bu nedenle, iplik eğrilmesinin ek yükünü önlerken, iptali gerekiyorsa, bir BackgroundWorkerveya (büyük olasılıkla UI dışında) kullanın, bir ipliği döndürün ve arayabilmeniz için bir referans tutun Abort().


1
Sadece ... umarım uygulama dişli bir görevi durdurmak için temiz bir yöntem hakkında tasarlanmıştır (İptal genellikle değil)

11

Ayrıca, arka plan işçisinin ömrü boyunca, yalnızca sınırlı sayıda olduğu için endişe verici olabilecek bir threadpool ipliği bağlıyorsunuz. Uygulamanız için yalnızca bir kez iş parçacığı oluşturuyorsanız (ve arka plan çalışanının özelliklerinden herhangi birini kullanmıyorsanız), daha sonra bir arka plan işçisi / iş parçacığı iş parçacığı yerine bir iş parçacığı kullandığınızı söyleyebilirim.


1
Bence bu iyi bir nokta. Bu nedenle, Formun ömrü boyunca "geçici olarak" bir arka plan iş parçacığı gerekiyorsa, ancak formun tüm yaşam süresi için bir arka plan iş parçacığı gerekiyorsa (dakika, saat, gün ...) daha sonra ThreadPool'un amacını kötüye kullanmamak için BackgroundWorker yerine bir Konu kullanın
freddy smith

"... sadece sonlu sayıda olduğu için endişe verici olabilir" ile ilgili olarak, işletim sistemindeki diğer uygulamaların bunlara ihtiyacı olabileceğini ve aynı 'havuzdan' paylaşabileceğini mi kastediyorsunuz?
Dan W

8

Windows Forms, WPF veya herhangi bir teknolojiyi kullansanız da, bazen BackgroundWorker ile çalışmak daha kolaydır. Bu adamlar hakkında düzgün kısmı, iş parçacığının nerede yürütüldüğü hakkında çok fazla endişelenmenize gerek kalmadan iplik geçirmenizdir, bu da basit görevler için harika.

BackgroundWorkerBir iş parçacığını iptal etmek istiyorsanız önce bir düşünmeyi kullanmadan önce (uygulamayı kapatma, kullanıcı iptali), iş parçacığınızın iptal olup olmadığını kontrol edip etmeyeceğine veya yürütmenin kendisine itilip itilmeyeceğine karar vermeniz gerekir.

BackgroundWorker.CancelAsync()ayarlayacak CancellationPending, trueancak daha fazla bir şey yapmayacak, o zaman sürekli olarak bunu kontrol etmek iş parçacığının sorumluluğundadır, ayrıca kullanıcının iptal ettiği bu yaklaşımda bir yarış koşulu ile sonuçlanabileceğinizi unutmayın, ancak iş parçacığı testten önce tamamlanmıştır. CancellationPending.

Thread.Abort() Öte yandan, iş parçacığının iptalini zorlayan iş parçacığı yürütme içinde bir istisna atar, ancak bu istisna yürütmede aniden ortaya çıkarsa neyin tehlikeli olabileceğine dikkat etmelisiniz.

Daha fazla okuma için, iş ne olursa olsun diş çekme işleminin çok dikkatli bir şekilde ele alınması gerekir:

.NET Framework Paralel Programlama Yönetilen Threading İyi Uygulamalar


5

Ben .NET bilmeden önce iş parçacığı nasıl kullanılacağını biliyordum, bu yüzden BackgroundWorkers kullanmaya başladığınızda alışmak biraz zaman aldı . Matt Davis, farkı mükemmeliyetle özetledi, ancak kodun tam olarak ne yaptığını anlamanın daha zor olduğunu ve hata ayıklamayı zorlaştıracağını da ekleyeceğim. Bir IMO iş parçacığı oluşturmayı ve kapatmayı düşünmek, bir iş parçacığı havuzuna iş vermeyi düşünmekten daha kolaydır.

Hala başkalarının gönderilerini yorumlayamıyorum, bu yüzden piers adresine bir cevap kullanarak anlık topallığımı affet7

Bunun Thread.Abort();yerine kullanmayın , bir olayı işaretleyin ve iş parçacığınızı sinyal verildiğinde zarif bir şekilde sonlanacak şekilde tasarlayın. iş parçacığının yürütülmesinde, yetim Monitörler, bozuk paylaşılan durum vb.Gibi her türlü mutsuz şeyi yapabilen keyfi bir noktada bir Thread.Abort()yükseltir ThreadAbortException.
http://msdn.microsoft.com/en-us/library/system.threading.thread.abort.aspx


2

Eğer kırılmazsa - o zamana kadar düzeltin ... sadece şaka yapıyorum :)

Ama ciddi olarak BackgroundWorker muhtemelen sahip olduğunuza çok benziyor, başlangıçtan başlamış olsaydınız belki biraz zaman kazanırdınız - ama bu noktada ihtiyacı görmüyorum. Bir şey işe yaramazsa veya mevcut kodunuzun anlaşılması zor değilse, sahip olduklarınıza sadık kalacağım.


2

Temel fark, belirttiğiniz gibi, 'den GUI olayları oluşturmaktır BackgroundWorker. İş parçacığının ekranı güncellemesi veya ana GUI iş parçacığı için olaylar oluşturması gerekmiyorsa, basit bir iş parçacığı olabilir.


2

Henüz bahsedilmeyen BackgroundWorker sınıfının bir davranışına işaret etmek istiyorum. Thread.IsBackground özelliğini ayarlayarak normal bir Thread'in arka planda çalışmasını sağlayabilirsiniz.

Arka plan iş parçacıkları, arka plan iş parçacıklarının bir işlemin sona ermesini engellememesi dışında, ön plan iş parçacıklarıyla aynıdır. [ 1 ]

Bu davranışı, form pencerenizin yapıcısında aşağıdaki yöntemi çağırarak test edebilirsiniz.

void TestBackgroundThread()
{
    var thread = new Thread((ThreadStart)delegate()
    {
        long count = 0;
        while (true)
        {
            count++;
            Debug.WriteLine("Thread loop count: " + count);
        }
    });

    // Choose one option:
    thread.IsBackground = true; // <--- This will make the thread run in background
    thread.IsBackground = false; // <--- This will delay program termination

    thread.Start();
}

IsBackground özelliği true olarak ayarlandığında ve pencereyi kapattığınızda, uygulamanız normal olarak sonlanır.

Ancak IsBackground özelliği false (varsayılan olarak) olarak ayarlandığında ve pencereyi kapattığınızda, yalnızca pencere kaybolur, ancak işlem yine de çalışmaya devam eder.

BackgroundWorker sınıfı, arka planda çalışan bir İş Parçacığı kullanır.


1

Arka plan çalışanı ayrı bir iş parçacığında çalışan bir sınıftır, ancak basit bir İş Parçacığı ile elde edemeyeceğiniz ek işlevsellik sağlar (görev ilerleme raporu işleme gibi).

Bir arka plan çalışanı tarafından verilen ek özelliklere ihtiyacınız yoksa - ve öyle görünmüyorsa - bir Konu daha uygun olacaktır.


-1

Benim için şaşırtıcı olan şey, görsel stüdyo tasarımcısının sadece hizmet projesiyle gerçekten çalışmayan BackgroundWorkers ve Timers'ı kullanmanıza izin vermesidir.

Hizmetinize düzgün sürükle ve bırak denetimleri verir, ancak ... dağıtmayı bile denemeyin. Çalışmaz.

Hizmetler: Sadece System.Timers.Timer kullanın System.Windows.Forms.Timer araç kutusunda bulunsa bile çalışmaz

Hizmetler: BackgroundWorkers bir hizmet olarak çalışırken çalışmaz Sistem Kullanın.Tişleme.Gerçekİçme Havuzları veya Async çağrıları

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.