C# 在.NET中是否有用于长时间运行线程的线程调度程序?

C# 在.NET中是否有用于长时间运行线程的线程调度程序?,c#,.net,multithreading,C#,.net,Multithreading,我们的场景是一个网络扫描仪 它连接到一组主机,并使用低优先级后台线程并行扫描它们一段时间 我希望能够安排大量的工作,但只有任何给定的,比如说十个或任意数量的主机并行扫描。即使我创建自己的线程,许多回调和其他异步线程也会使用线程池,最终我会耗尽资源。我应该看看MonoTorrent 如果我使用ThreadPool,我是否可以将我的应用程序限制在某个数量上,以使应用程序的其余部分能够顺利运行 是否有一个线程池可以初始化为n个长寿命线程 [编辑] 似乎没有人注意到我对一些回复发表了一些评论,所以我将在

我们的场景是一个网络扫描仪

它连接到一组主机,并使用低优先级后台线程并行扫描它们一段时间

我希望能够安排大量的工作,但只有任何给定的,比如说十个或任意数量的主机并行扫描。即使我创建自己的线程,许多回调和其他异步线程也会使用线程池,最终我会耗尽资源。我应该看看MonoTorrent

如果我使用ThreadPool,我是否可以将我的应用程序限制在某个数量上,以使应用程序的其余部分能够顺利运行

是否有一个线程池可以初始化为n个长寿命线程

[编辑] 似乎没有人注意到我对一些回复发表了一些评论,所以我将在这里补充几点

  • 两个线程都应该是可取消的 优雅而有力
  • 线程应具有低优先级,使GUI响应
  • 线程长时间运行,但按顺序(分钟)而不是顺序(天)
给定目标主机的工作基本上是:

  For each test
    Probe target (work is done mostly on the target end of an SSH connection)
    Compare probe result to expected result (work is done on engine machine)
  Prepare results for host
有人能解释为什么使用SmartThreadPool被标记为负面有用吗?

CLR不适合执行长时间运行的任务:它用于执行短任务,而创建线程的成本几乎与执行方法本身一样高。(或者至少占执行该方法所需时间的很大一部分。)正如您所看到的,.NET本身消耗线程池线程,您不能为自己保留一块线程池线程,以免您冒着耗尽运行时的风险


调度、限制和取消工作是另一回事。没有其他内置的.NET worker队列线程池,因此您将拥有自己的(管理或自己)或找到一个先前存在的线程池(看起来很有希望,尽管我自己没有使用过)。

使用内置的线程池。它具有良好的性能


或者,您可以查看或,以了解最大工作线程数的限制。

在.NET 4中,您有集成的。创建新任务(新线程抽象)时,可以将任务指定为长时间运行。我们在这方面取得了很好的经验(长时间的工作,而不是几分钟或几小时)

您也可以在.NET2中使用它,但实际上它是一个扩展,请检查

在VS2010中,基于任务(而非线程)的并行应用程序调试得到了根本性的改进。建议尽可能使用任务,而不是原始线程。因为它可以让您以更面向对象的友好方式处理并行性

更新
未指定为长时间运行的任务将排队进入线程池(或任何其他调度程序)。

但是如果一个任务被指定为长时间运行,它只会创建一个独立的线程,而不涉及线程池。在您的特定情况下,最好的选择不是线程或线程池或后台工作线程,而是异步编程模型(BeginXXX,EndXXX)由框架提供

使用的优点是,只要有数据要读取,TcpIp堆栈就会使用回调,并且回调会自动在线程池中的线程上运行

使用,可以控制每个启动时间间隔的请求数,如果需要,还可以在正常优先级线程上处理请求时,从低优先级线程启动所有请求,这意味着数据包将尽可能少地保留在网络堆栈的内部Tcp队列中


另外,对于不分配计算但主要在IO(网络、磁盘等)上等待的多个并发和长时间运行的作业,更好的选择始终是使用回调机制,而不是线程。

我会创建自己的线程管理器。在下面的简单示例中,队列用于保存等待的线程,字典用于保存活动线程,由ManagedThreadId设置密钥。当一个线程完成时,它将自己从活动字典中移除,并通过回调启动另一个线程

您可以从UI更改最大运行线程限制,并且可以将额外信息传递给ThreadDone回调以监视性能等。如果线程因网络超时而失败,您可以重新插入队列。向主管添加额外的暂停、停止等控制方法

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

namespace ConsoleApplication1
{
    public delegate void CallbackDelegate(int idArg);

    class Program
    {
        static void Main(string[] args)
        {
            new Supervisor().Run();
            Console.WriteLine("Done");
            Console.ReadKey();
        }
    }

    class Supervisor
    {
        Queue<System.Threading.Thread> waitingThreads = new Queue<System.Threading.Thread>();
        Dictionary<int, System.Threading.Thread> activeThreads = new Dictionary<int, System.Threading.Thread>();
        int maxRunningThreads = 10;
        object locker = new object();
        volatile bool done;

        public void Run()
        {
            // queue up some threads
            for (int i = 0; i < 50; i++)
            {
                Thread newThread = new Thread(new Worker(ThreadDone).DoWork);
                newThread.IsBackground = true;
                waitingThreads.Enqueue(newThread);
            }
            LaunchWaitingThreads();
            while (!done) Thread.Sleep(200);
        }

        // keep starting waiting threads until we max out
        void LaunchWaitingThreads()
        {
            lock (locker)
            {
                while ((activeThreads.Count < maxRunningThreads) && (waitingThreads.Count > 0))
                {
                    Thread nextThread = waitingThreads.Dequeue();
                    activeThreads.Add(nextThread.ManagedThreadId, nextThread);
                    nextThread.Start();
                    Console.WriteLine("Thread " + nextThread.ManagedThreadId.ToString() + " launched");
                }
                done = (activeThreads.Count == 0) && (waitingThreads.Count == 0);
            }
        }

        // this is called by each thread when it's done
        void ThreadDone(int threadIdArg)
        {
            lock (locker)
            {
                // remove thread from active pool
                activeThreads.Remove(threadIdArg);
            }
            Console.WriteLine("Thread " + threadIdArg.ToString() + " finished");
            LaunchWaitingThreads(); // this could instead be put in the wait loop at the end of Run()
        }
    }

    class Worker
    {
        CallbackDelegate callback;
        public Worker(CallbackDelegate callbackArg)
        {
            callback = callbackArg;
        }

        public void DoWork()
        {
            System.Threading.Thread.Sleep(new Random().Next(100, 1000));
            callback(System.Threading.Thread.CurrentThread.ManagedThreadId);
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用系统线程;
命名空间控制台应用程序1
{
公共委托void CallbackDelegate(int-idArg);
班级计划
{
静态void Main(字符串[]参数)
{
新主管().Run();
控制台。写入线(“完成”);
Console.ReadKey();
}
}
班主任
{
Queue waitingThreads=新队列();
Dictionary activeThreads=新字典();
int maxRunningThreads=10;
对象锁定器=新对象();
挥发性有机物;
公开募捐
{
//将一些线程排队
对于(int i=0;i<50;i++)
{
线程newThread=新线程(新工作线程(ThreadDone).DoWork);
newThread.IsBackground=true;
排队(newThread);
}
启动WaitingThreads();
while(!done)Thread.Sleep(200);
}
//继续等待线程,直到达到最大值
void LaunchWaitingThreads()
{
锁(储物柜)
{
而((activeThreads.Count0))
{
Thread nextThread=waitingThreads.Dequeue();
添加(nexthread.ManagedThreadId,nexthread);