核心数量和线程数量之间的关系:我能够创建多少个线程?

3

我有一颗英特尔四核CPU。

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

是否存在核心数和同时运行的最大线程数之间的相关性?我需要找出任何时候有多少个线程正在运行,如果是这样,是否可能?(我知道有像最小和最大线程这样的属性)?这会取决于线程池吗(此池中的最大线程数是否会更改)?这是这篇帖子/线程的C#部分。


你打算生成多少个线程?如果你担心有任何限制,那么你可能生成的线程太多了。 - Tai Squared
我还没有生成任何东西。这只是假设和未来的事情(我非常好奇,很多问题与我目前的开发无关)。我想了解理论。 - GurdeepS
5个回答

12

这完全取决于情况,如果您的线程活跃(而不是等待IO)100%的时间,那么每个CPU多于1个线程就没有什么意义。然而,除非进行复杂的数值计算,否则很少有这种情况。

.NET的线程池具有:http://msdn.microsoft.com/en-us/library/system.threading.threadpool.aspx

线程池默认每个可用处理器具有250个工作线程和1000个I/O完成线程。

因此,除了:

  • 测量、测量、再测量。

我想说的是,几乎没有人可以给出什么建议。

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


1
+1 寻找线程的最佳点可能是最简单的分析任务之一。您只需要在大多数消费者机器上尝试约20个数据点,就可以看到一个非常明显的趋势,通常10个就足够了。由于这个数字将完全取决于线程正在做什么以及系统所有组件的规格,因此这确实是唯一的方法。 - ShuggyCoUk

1

必须测量。话虽如此,使用N个核心时,我通常通过生成N+12N个线程来获得最佳结果。但是你必须测量。


0
“我能生成多少线程?”
远远超过(数百或数千倍)您希望生成的最佳吞吐量。
我所知道的(在Windows上)每个线程的限制是:
- 16位线程ID - 用户空间堆栈的4-8KB分配(通常要大得多) - 非可页面内核空间上下文和堆栈,大约16KB
Dotnet可能会为其自己的内容添加大量每个线程的开销。例如GC等。
我喜欢使用一个WAG公式:
threads = 2 * (cpu cores + active disk spindles)

最佳数量通常是那个数量的两倍左右。理论上,所需线程数与 CPU 核心数成比例(出于显而易见的原因),但也有一些线程会在磁盘 I/O 上阻塞。乘以二可以让 CPU 在其他线程被阻塞时有事可做。

总之,从这个数字开始并进行测量。工作线程的数量是整个问题中最容易调整的部分,所以现在不要太担心它。


0

我想知道启动多个线程会首先达到哪个限制。我编写了以下简单的测试程序并进行了尝试。现在我认为内存是限制因素。我能够运行1000个线程,但没有使用Thread.Sleep()时,系统变得“有点不响应”。使用2000个线程后,在启动约1800个线程后,我遇到了内存不足异常。(笔记本电脑配备Intel Core 2 Duo T5800 2.0 GHz、3.0 GiB RAM和在Windows XP SP3上运行的“几个”应用程序,使用.NET Framework 3.5 SP1)

更新

内存不足异常是由于线程的堆栈引起的。在线程构造函数中指定堆栈大小(我使用了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);
            }
        }
    }
}

0

虽然线程和核心之间存在松散的关联(线程要想真正并发执行的唯一方法是在不同的核心上运行,但这种知识比你想象中的价值更低),但实际工作是由操作系统调度程序完成的,在这种情况下是Windows的线程调度程序。

至于可以创建多少个线程,这将因系统而异。ThreadPool类不会对生成自己的线程设置任何限制;它具有一个池子管理自身内部线程。这些是您检查ThreadPool类属性时可以看到的值。不过,您不应该产生无限制的线程;最终,操作系统会花费更多时间在您的线程之间进行切换,而不是实际允许您的线程运行。通过基准测试找出适合您的应用程序的线程数量。

您究竟想做什么?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接