如何动态创建一定数量的线程,并在C#中完成任何线程时分配方法

本文关键字:线程 并在 方法 分配 任何 动态 何动态 创建 | 更新日期: 2023-09-27 18:27:07

我有一个场景,需要根据可配置变量动态创建线程数。我一次只能启动那个数量的线程,一旦其中一个线程完成,我就需要在和队列中相同的线程中分配一个方法。

有谁能帮我举个例子来解决上述情况吗。

我已经研究了一个星期,但没能找到具体的解决方案。

如何动态创建一定数量的线程,并在C#中完成任何线程时分配方法

有很多方法可以解决这个问题,但哪种方法最好取决于您的具体问题。

但是,让我们假设您有一个要进行某些工作的项目集合,每个项目由一个单独的线程处理,最多可以同时处理您指定的最大数量的线程。

一种非常简单的方法是通过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可能会带来更好的解决方案,但您明确要求使用线程。