如何在.NET 3.5中重用线程

我有一个处理大块信息的子程序。 为了利用整个CPU,它将工作分为单独的线程。 完成所有线程后,它就完成了。 我读到创建和销毁线程会占用大量开销,所以我尝试使用线程池,但实际上运行速度比创建自己的线程慢。 如何在程序运行时创建自己的线程,然后继续重用它们? 我见过有些人说它无法完成,但是线程池是这样做的,所以它必须是可能的,对吧?

以下是启动新线程/使用线程池的代码的一部分:

//initialization for threads Thread[] AltThread = null; if (NumThreads > 1) AltThread = new Thread[pub.NumThreads - 1]; do { if (NumThreads > 1) { //split the matrix up into NumThreads number of even-sized blocks and execute on separate threads int ThreadWidth = DataWidth / NumThreads; if (UseThreadPool) //use threadpool threads { for (int i = 0; i  0); } else //create new threads each time (can we reuse these?) { for (int i = 0; i < NumThreads - 1; i++) { AltThread[i] = new Thread(ComputePartialDataOnThread); AltThread[i].Start(new object[] { AltEngine[i], ThreadWidth * (i + 1), ThreadWidth * (i + 2) }); } ComputePartialData(ThisEngine, 0, ThreadWidth); //wait for all threads to finish foreach (Thread t in AltThread) t.Join(1000); foreach (Thread t in AltThread) if (t.IsAlive) t.Abort(); } } } 

ComputePartialDataOnThread只需解压缩信息并调用ComputePartialData。 将要处理的数据在线程之间共享(它们不会尝试读/写相同的位置)。 AltEngine []是每个线程的独立计算引擎。

使用线程池运行大约10-20%。

这听起来像一个相当普遍的要求,可以通过multithreading生产者 – 消费者队列来解决。 线程保持“活动”状态,并在将新工作添加到队列时发出信号以进行工作。 工作由委托(在您的情况下为ComputePartialDataOnThread)表示,传递给委托的数据是排队的(在您的情况下是ComputePartialDataOnThread的参数)。 有用的特性是管理工作线程和实际算法的实现是分开的。 这是pc队列:

 public class SuperQueue : IDisposable where T : class { readonly object _locker = new object(); readonly List _workers; readonly Queue _taskQueue = new Queue(); readonly Action _dequeueAction; ///  /// Initializes a new instance of the  class. ///  /// The worker count. /// The dequeue action. public SuperQueue(int workerCount, Action dequeueAction) { _dequeueAction = dequeueAction; _workers = new List(workerCount); // Create and start a separate thread for each worker for (int i = 0; i < workerCount; i++) { Thread t = new Thread(Consume) { IsBackground = true, Name = string.Format("SuperQueue worker {0}",i )}; _workers.Add(t); t.Start(); } } ///  /// Enqueues the task. ///  /// The task. public void EnqueueTask(T task) { lock (_locker) { _taskQueue.Enqueue(task); Monitor.PulseAll(_locker); } } ///  /// Consumes this instance. ///  void Consume() { while (true) { T item; lock (_locker) { while (_taskQueue.Count == 0) Monitor.Wait(_locker); item = _taskQueue.Dequeue(); } if (item == null) return; // run actual method _dequeueAction(item); } } ///  /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. ///  public void Dispose() { // Enqueue one null task per worker to make each exit. _workers.ForEach(thread => EnqueueTask(null)); _workers.ForEach(thread => thread.Join()); } } 

正如之前的海报所说,有许多内置结构(查看TPL),它们使用Threadpool,您可能希望在实现自己的队列之前查看它。

所以通常的做法是让每个线程的入口点基本上做类似的事情(这只是一个算法,而不是C#代码,对不起):

  1. 检查你是否有工作要做
  2. 找到工作
  3. 等待信号

另一方面,每当你为你的线程做更多的工作时,将它添加到要做的工作队列中,然后你的线程本质上被重用。 这非常类似于人们如何自己实现一个线程池(如果你在运行时你可以做一些其他事情来帮助你,但这不是一个超级大事)。

这是一个讨论这个问题的线程 : 自定义线程池/队列类。