Dot-Net

在控制台應用程序中使用 .NET BackgroundWorker 類

  • February 19, 2022

一般來說,我對 .NET 程式和多執行緒比較陌生,想知道是否可以使用 .NET 提供的 BackgroundWorker 來生成工作執行緒以在控制台應用程序中執行某些工作?從線上的各種文件中,我看到這個類的意圖更多的是面向 UI 的應用程序,你想在後台做一些工作,但保持 UI 響應,並報告進度,如果需要取消處理等。

就我而言,基本上我有一個控制器類,我想在其中產生多個工作執行緒來進行一些處理(限制使用信號量產生的工作執行緒的最大數量)。然後我希望我的控制器類阻塞,直到所有執行緒都完成處理。所以在我啟動一個工作執行緒做一些工作之後,我希望執行緒能夠在處理完成時通知控制器執行緒。我看到我可以使用後台工作類,並處理 DoWork 和 RunWorkerCompleted 事件來完成此任務,但是想知道這是否是個好主意?有沒有更好的方法來實現這一目標?

這在控制台應用程序中不起作用,因為SynchronizationContext.Current永遠不會被初始化。當您使用 GUI 應用程序時,這是由 Windows 窗體或 WPF 為您初始化的。

話雖如此,沒有理由這樣做。只需使用ThreadPool.QueueUserWorkItem和一個重置事件(ManualResetEventAutoResetEvent)來擷取完成狀態,並阻塞你的主執行緒。


編輯:

在看到一些OP評論後,我想我會添加這個。

在我看來,“最好”的替代方案是獲取Rx Framework的副本,因為它包含 .NET 4 中 TPL 的反向移植。這將允許您使用提供選項的Parallel.ForEach的重載提供一個ParallelOptions實例。這將允許您限制並發操作的總數,並為您處理所有工作:

// using collection of work items, such as: List<Action<object>> workItems;
var options = new ParallelOptions();
options.MaxDegreeOfParallelism = 10; // Restrict to 10 threads, not recommended!

// Perform all actions in the list, in parallel
Parallel.ForEach(workItems, options, item => { item(null); });

但是,使用 Parallel.ForEach,我個人會讓系統管理並行度。它將自動分配適當數量的執行緒(尤其是當/如果它移動到 .NET 4 時)。

如果您的要求只是阻塞直到所有執行緒都完成,那真的很容易 - 只需啟動新執行緒然後呼叫Thread.Join它們中的每一個:

using System;
using System.Collections.Generic;
using System.Threading;

public class Test
{
   static void Main()
   {
       var threads = new List<Thread>();
       for (int i = 0; i < 10; i++)
       {
           int copy = i;
           Thread thread = new Thread(() => DoWork(copy));
           thread.Start();
           threads.Add(thread);
       }

       Console.WriteLine("Main thread blocking");
       foreach (Thread thread in threads)
       {
           thread.Join();
       }
       Console.WriteLine("Main thread finished");
   }

   static void DoWork(int thread)
   {
       Console.WriteLine("Thread {0} doing work", thread);
       Random rng = new Random(thread); // Seed with unique numbers
       Thread.Sleep(rng.Next(2000));
       Console.WriteLine("Thread {0} done", thread);
   }
}

編輯:如果您可以訪問 .NET 4.0,那麼 TPL 絕對是正確的選擇。否則,我建議使用生產者/消費者隊列(周圍有很多範常式式碼)。基本上,您有一個工作項隊列,以及與核心一樣多的消費者執行緒(假設它們受 CPU 限制;您希望根據您的工作負載對其進行定制)。每個消費者執行緒都會從隊列中取出項目並處理它們,一次一個。具體如何管理這將取決於您的情況,但這並不是非常複雜。如果你能想出開始時需要做的所有工作,那就更容易了,這樣執行緒就可以在發現隊列為空時退出。

引用自:https://stackoverflow.com/questions/2196204