C# ThreadPool在几秒钟内就使用了过多的内存

C# ThreadPool在几秒钟内就使用了过多的内存,c#,threadpool,C#,Threadpool,我制作了一个简单的控制台应用程序,用于打印素数。我使用ThreadPool函数来检查一个数字是否为素数 在任务管理器中,此程序开始占用太多内存(几秒钟内占用1 GB) 如果我仍然必须使用ThreadPool,我该如何改进这一点 这是我写的代码 class Program { static void Main(string[] args) { Console.WriteLine(2); Console.WriteLine(3); Co

我制作了一个简单的控制台应用程序,用于打印素数。我使用ThreadPool函数来检查一个数字是否为素数

在任务管理器中,此程序开始占用太多内存(几秒钟内占用1 GB) 如果我仍然必须使用ThreadPool,我该如何改进这一点

这是我写的代码

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(2);
        Console.WriteLine(3);
        Console.WriteLine(5);
        Console.WriteLine(7);
        Console.WriteLine(11);
        Console.WriteLine(13);
        Console.WriteLine(17);
        for (long i = 19; i < Int64.MaxValue; i = i+2)
        {
            if(i % 3 == 0 || i % 5 == 0 || i % 7 == 0 || i % 11 == 0 || i % 13 == 0 || i % 17 == 0 )
                continue;

            ThreadPool.QueueUserWorkItem(CheckForPrime, i);
        }
        Console.Read();
    }

    private static void CheckForPrime(object i)
    {
        var i1 = i as long?;
        var val =  Math.Sqrt(i1.Value);
        for (long j = 19; j <= val; j = j + 2)
        {
            if (i1 % j == 0) return;
        }
        Console.WriteLine(i1);

    }
}
类程序
{
静态void Main(字符串[]参数)
{
控制台写入线(2);
控制台写入线(3);
控制台写入线(5);
控制台写入线(7);
控制台写入线(11);
控制台写入线(13);
控制台写入线(17);
用于(长i=19;i对于(长j=19;j您正在循环中创建
线程,没有任何中断。您应该给创建线程的过程一些中断,以便在
线程池中创建更多线程之前,一些线程完成其执行。您可以使用它

for (long i = 19; i < Int64.MaxValue; i = i+2)
{
      if(i % 3 == 0 || i % 5 == 0 || i % 7 == 0 || i % 11 == 0 || i % 13 == 0 || i % 17 == 0 )
            continue;
      ThreadPool.QueueUserWorkItem(CheckForPrime, i);
      System.Threading.Thread.Sleep(100);
}
for(长i=19;i

您应该知道在何处使用线程,它们将是有益的,您需要多少线程,以及线程对应用程序性能的影响。这取决于应用程序暂停当前线程的时间。我只给了100毫秒,您可以根据应用程序进行调整。

您是crea在循环中不间断地执行
线程。您应该在创建线程的过程中给予一些中断,以便在
线程池中创建更多线程之前,一些线程完成其执行。您可以使用

for (long i = 19; i < Int64.MaxValue; i = i+2)
{
      if(i % 3 == 0 || i % 5 == 0 || i % 7 == 0 || i % 11 == 0 || i % 13 == 0 || i % 17 == 0 )
            continue;
      ThreadPool.QueueUserWorkItem(CheckForPrime, i);
      System.Threading.Thread.Sleep(100);
}
for(长i=19;i

您应该知道在何处使用线程,它们将是有益的,您需要多少线程,以及线程对应用程序性能的影响。这取决于应用程序暂停当前线程的时间。我只给了100毫秒,您可以根据您的应用程序进行调整。

坦白地说,你做的多线程是错误的。线程在正确使用时是一个强大的工具,但和所有工具一样,它们并不是所有情况下的正确解决方案。玻璃瓶可以盛放啤酒,但对于钉钉子却不是那么好

在一般情况下,创建更多线程并不会使运行速度更快,正如您所发现的,这一点在这里尤其正确。您编写的代码在循环的每个迭代中都会将一个新线程排队,并且这些线程中的每个线程都将分配一个堆栈。由于.NET世界中堆栈的默认大小为1 MB,因此不会要花很长时间才能让你的内存投入猛增。因此,超过1GB也就不足为奇了。最终,你会遇到一个硬内存限制,并引发一个
OutOfMemoryException
。而内存正是最明显的资源,你的设计很快就会让你的系统陷入饥饿。除非如果您的系统资源可以随着线程池呈指数级增长,您将不会体验到任何性能优势

插入对
Thread.Sleep
的调用,为创建的新线程留出运行时间,然后再继续循环(并创建其他线程)。正如我在评论中提到的,尽管这“有效”,对我来说,这似乎是一个非常丑陋的黑客行为。但我很难提出更好的解决方案,因为真正的问题是设计。你说你必须使用线程池,但你没有说为什么会这样

如果您必须使用线程池,最好的解决方法可能是对线程池的大小设置任意限制(即它可以生成多少个新线程),这可以通过调用来完成。这至少比
thread.Sleep
让我感觉不那么烦人

注意:如果您决定采用
SetMaxThreads
方法,您应该知道不能将最大值设置为小于最小值。最小值的默认值是CPU内核数,因此如果您使用双核处理器,则在不先降低最小值的情况下,无法将最大值设置为1

最后,尽管在本例中它并没有真正改变答案,但值得注意的是,Task Manager不是一个内存探查器。像使用内存探查器一样依赖它会经常得到错误(或至少是非常误导)的数据


编辑:经过进一步思考,我发现问题其实不在于指数执行,而在于指数查询。允许的最大线程数可能与此无关,因为代码仍将以比预期处理速度更快的速度排队。因此,不要介意限制大小。您可以可能需要创建一个信号量,或者每个人都暗示不要使用线程池。

坦率地说,多线程是错误的。线程在正确使用时是一个强大的工具,但与所有工具一样,它们不是每种情况下都正确的解决方案。玻璃瓶可以工作对h来说很好