我有一颗英特尔四核CPU。
如果我要开发一个仅在我的机器上使用的Winforms应用程序(我使用C#),我最多可以生成多少个线程?
是否存在核心数和同时运行的最大线程数之间的相关性?我需要找出任何时候有多少个线程正在运行,如果是这样,是否可能?(我知道有像最小和最大线程这样的属性)?这会取决于线程池吗(此池中的最大线程数是否会更改)?这是这篇帖子/线程的C#部分。
我有一颗英特尔四核CPU。
如果我要开发一个仅在我的机器上使用的Winforms应用程序(我使用C#),我最多可以生成多少个线程?
是否存在核心数和同时运行的最大线程数之间的相关性?我需要找出任何时候有多少个线程正在运行,如果是这样,是否可能?(我知道有像最小和最大线程这样的属性)?这会取决于线程池吗(此池中的最大线程数是否会更改)?这是这篇帖子/线程的C#部分。
这完全取决于情况,如果您的线程活跃(而不是等待IO)100%的时间,那么每个CPU多于1个线程就没有什么意义。然而,除非进行复杂的数值计算,否则很少有这种情况。
.NET的线程池具有:http://msdn.microsoft.com/en-us/library/system.threading.threadpool.aspx
线程池默认每个可用处理器具有250个工作线程和1000个I/O完成线程。
因此,除了:
我想说的是,几乎没有人可以给出什么建议。
在某些时候,当您添加更多线程时,由于上下文切换和同步,事情会变慢。
你必须测量。话虽如此,使用N个核心时,我通常通过生成N+1到2N个线程来获得最佳结果。但是你必须测量。
threads = 2 * (cpu cores + active disk spindles)
最佳数量通常是那个数量的两倍左右。理论上,所需线程数与 CPU 核心数成比例(出于显而易见的原因),但也有一些线程会在磁盘 I/O 上阻塞。乘以二可以让 CPU 在其他线程被阻塞时有事可做。
总之,从这个数字开始并进行测量。工作线程的数量是整个问题中最容易调整的部分,所以现在不要太担心它。
我想知道启动多个线程会首先达到哪个限制。我编写了以下简单的测试程序并进行了尝试。现在我认为内存是限制因素。我能够运行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);
}
}
}
}
虽然线程和核心之间存在松散的关联(线程要想真正并发执行的唯一方法是在不同的核心上运行,但这种知识比你想象中的价值更低),但实际工作是由操作系统调度程序完成的,在这种情况下是Windows的线程调度程序。
至于可以创建多少个线程,这将因系统而异。ThreadPool类不会对生成自己的线程设置任何限制;它具有一个池子管理自身内部线程。这些是您检查ThreadPool类属性时可以看到的值。不过,您不应该产生无限制的线程;最终,操作系统会花费更多时间在您的线程之间进行切换,而不是实际允许您的线程运行。通过基准测试找出适合您的应用程序的线程数量。
您究竟想做什么?