如何动态创建一定数量的线程,并在C#中完成任何线程时分配方法
本文关键字:线程 并在 方法 分配 任何 动态 何动态 创建 | 更新日期: 2023-09-27 18:27:07
我有一个场景,需要根据可配置变量动态创建线程数。我一次只能启动那个数量的线程,一旦其中一个线程完成,我就需要在和队列中相同的线程中分配一个方法。
有谁能帮我举个例子来解决上述情况吗。
我已经研究了一个星期,但没能找到具体的解决方案。
有很多方法可以解决这个问题,但哪种方法最好取决于您的具体问题。
但是,让我们假设您有一个要进行某些工作的项目集合,每个项目由一个单独的线程处理,最多可以同时处理您指定的最大数量的线程。
一种非常简单的方法是通过AsParallel()
和WithDegreeOfParallelism()
使用Plinq,如下控制台应用程序所示:
using System;
using System.Linq;
using System.Threading;
namespace Demo
{
static class Program
{
static void Main()
{
int maxThreads = 4;
var workItems = Enumerable.Range(1, 100);
var parallelWorkItems = workItems.AsParallel().WithDegreeOfParallelism(maxThreads);
parallelWorkItems.ForAll(worker);
}
static void worker(int value)
{
Console.WriteLine($"Worker {Thread.CurrentThread.ManagedThreadId} is processing {value}");
Thread.Sleep(1000); // Simulate work.
}
}
}
如果运行此程序并检查输出,您将看到多个线程正在处理工作项,但线程的最大数量被限制在指定值内。
您应该了解线程池。请参阅此链接以了解.NET中的线程冷却的更多信息。您很可能必须使用回调来完成任务,以便在一个线程中完成工作后立即调用方法。
使用async/await
可能会有一个更智能的解决方案,具体取决于您想要实现的目标。但是,由于您明确询问了线程,这里有一个简短的类可以满足您的要求:
public class MutliThreadWorker : IDisposable
{
private readonly ConcurrentQueue<Action> _actions = new ConcurrentQueue<Action>();
private readonly List<Thread> _threads = new List<Thread>();
private bool _disposed;
private void ThreadFunc()
{
while (true)
{
Action action;
while (!_actions.TryDequeue(out action)) Thread.Sleep(100);
action();
}
}
public MutliThreadWorker(int numberOfThreads)
{
for (int i = 0; i < numberOfThreads; i++)
{
Thread t = new Thread(ThreadFunc);
_threads.Add(t);
t.Start();
}
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
_disposed = true;
foreach (Thread t in _threads)
t.Abort();
if (disposing)
GC.SuppressFinalize(this);
}
public void Enqueue(Action action)
{
if (_disposed)
throw new ObjectDisposedException("MultiThreadWorker");
_actions.Enqueue(action);
}
}
此类在实例化时启动所需数量的线程,如下所示:
int requiredThreadCount = 16; // your configured value
MultiThreadWorker mtw = new MultiThreadWorker(requiredThreadCount);
然后,它使用ConcurrentQueue<T>跟踪要做的任务。您可以通过将方法添加到队列中
mtw.Enqueue(() => DoThisTask());
我把它定为IDisposable
,以确保踏板最终停止<当然,这需要一点改进,因为像这样中止线程不是最好的做法>
ThreadFunc
本身重复检查是否有排队的动作并执行它们。这也可以通过使用Monitor、Pulse和Monitor、Wait等模式来稍微改进。
正如我所说,async/await
可能会带来更好的解决方案,但您明确要求使用线程。