核心与我可以产生的线程数之间的关系

时间:2009-08-03 22:50:50

标签: c# multithreading concurrency hardware

我有一个Intel四核CPU。

如果我要开发一个仅在我的机器上使用的Winforms应用程序(我使用C#btw),我可以生成多少个线程?

核心和我可以在任何时间运行的最大线程数之间是否存在某种相关性?我是否需要在任何时候找出有多少线程在运行?如果有,这可能吗? (我知道有最小和最大线程的属性)?这取决于线程池(此池中线程的最大数量是否会发生变化?)。这是帖子/帖子的C#部分。

5 个答案:

答案 0 :(得分:11)

所有依赖,如果您的线程在100%的时间内处于活动状态(而不是等待IO),那么每个CPU拥有更多的1个线程几乎没有意义。但是,除非您执行复杂的数值计算,否则很少会出现这种情况。

.Nets threadpool有:http://msdn.microsoft.com/en-us/library/system.threading.threadpool.aspx

  

线程池的默认大小为   每个可用250个工作线程   处理器,1000 I / O完成   线程。

所以,我想说,除了以下任何人都可以给你的建议很少:

  • 衡量措施措施。

在某些时候,由于上下文切换和同步,当您添加更多线程时内容会变慢

答案 1 :(得分:1)

必须衡量。也就是说,对于 N 核心,我通常会在 N + 1 2N 线程之间产生最佳结果。但你必须衡量。

答案 2 :(得分:0)

虽然线程和核心之间存在松散的关联(线程真正并发执行的唯一方法是让它们在不同的核心上运行,但这些知识的价值低于您的想象),真正的工作是由操作系统调度程序完成,在本例中是Windows中的线程调度程序。

关于您可以创建多少个线程,这将因系统而异。 ThreadPool类对产生自己的线程没有任何限制;它有一个很好的线程池,它在内部管理自己。这些是您在检查ThreadPool类的属性时可以看到的值。但是,这并不是说你应该产生无限的线程;最终,操作系统将花费更多时间在线程之间切换,而不是实际允许线程运行。通过基准测试确定适合您的应用程序的线程数。

你究竟想做什么?

答案 3 :(得分:0)

  

我可以产生多少个线程?

Waaay,比你想要产生的最佳吞吐量更多(数百或数千倍)。

我知道的每线程限制(在Windows上)是:

  • 16位线程ID
  • 用户空间堆栈的4-8KB分配(通常更多)
  • 不可分页的内核空间上下文和堆栈,类似16KB

Dotnet可能会为自己的东西增加一堆每线程开销。 GC等。

我喜欢用于WAG的一个公式是:

threads = 2 * (cpu cores + active disk spindles)

最佳数字通常在两倍之内。那个。理论上说,所需的线程对cpu核心是有利的(出于显而易见的原因),但也有一些线程会阻塞磁盘I / O.乘以2可以让CPU在阻止其他线程时执行某些操作。

无论如何,从那开始并测量它。工作线程的数量是整个问题中最容易调整的部分,所以现在不用担心太多。

答案 4 :(得分:0)

只是想知道通过启动多个线程首先会遇到什么限制。我编写了以下简单的测试程序并尝试了它。现在我假设记忆是限制因素。我能够运行1000个线程,但没有Thread.Sleep()系统变得“有点反应迟钝”。使用2000个线程后,我在启动大约1800个线程后出现内存不足异常。 (配备英特尔酷睿2双核T5800 2.0 GHz,3.0 GiB内存和“少数”应用程序的笔记本电脑在带有.NET Framework 3.5 SP1的WIndows XP SP3上运行)

<强>更新

内存不足异常是由线程堆栈引起的。在线程构造函数上指定堆栈大小之后(我使用64 kB但可能达到目前我不知道的最小大小)我能够启动3500个线程(Thread.Sleep())。

using System;
using System.Linq;
using System.Threading;

namespace GeneralTestApplication
{
    class Program
    {
        private static void Main()
        {
            Console.WriteLine("Enter the number of threads to start.");

            while (!Int32.TryParse(Console.ReadLine(), out Program.numberThreads)) { }

            Program.counters = new Int64[Program.numberThreads];

            Console.WriteLine("Starting {0} threads.", Program.numberThreads);

            for (Int32 threadNumber = 0; threadNumber < Program.numberThreads; threadNumber++)
            {
                new Thread(Program.ThreadMethod).Start(threadNumber);
            }

            Console.WriteLine("Press enter to perform work on all threads.");
            Console.ReadLine();

            Program.manualResetEvent.Set();

            Console.WriteLine("Press enter to stop all threads.");
            Console.ReadLine();

            Program.stop = true;

            Console.WriteLine("At least {0} threads ran.", Program.counters.Count(c => c > 0));

            Console.ReadLine();
        }

        private static Int32 numberThreads = 0;
        private static Int64[] counters = null;
        private static readonly ManualResetEvent manualResetEvent = new ManualResetEvent(false);
        private static volatile Boolean stop = false;

        public static void ThreadMethod(Object argument)
        {
            Int32 threadNumber = (Int32)argument;

            Program.manualResetEvent.WaitOne();

            while (!Program.stop)
            {
                Program.counters[threadNumber]++;

                // Uncomment to simulate heavy work.
                Thread.Sleep(10);
            }
        }
    }
}