我有一个简单的程序,它启动n个线程并在每个线程上创建一些负载.如果我只启动一个线程,则一个核心获得大约100%的负载.如果我用16个线程(这意味着每个核心一个线程)启动一个进程,我只能获得大约80%的负载.如果我用2个线程启动8个进程(这仍然意味着每个核心一个线程),我得到大约99%的负载.我在这个样本中没有使用任何锁定.
这种行为的原因是什么?据我所知,如果有100个线程正在工作,那么负载会下降,因为操作系统必须安排很多.但在这种情况下,只有核心数量的线程.
情况更糟(至少对我而言).如果我在循环中添加一个简单的thread.sleep(0),则一个进程和16个线程的负载增加到95%.
任何人都可以回答这个问题,或提供有关此特定主题的更多信息的链接吗?



//Sample application which reads the number of threads to be started from Console.ReadLine
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter the number of threads to be started");
int numberOfThreadsToStart;
string input = Console.ReadLine();
int.TryParse(input, out numberOfThreadsToStart);
if(numberOfThreadsToStart < 1)
{
Console.WriteLine("No valid number of threads entered. Exit now");
Thread.Sleep(1500);
return;
}
List<Thread> threadList = new List<Thread>();
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < numberOfThreadsToStart; i++)
{
Thread workerThread = new Thread(MakeSomeLoad);
workerThread.Start();
threadList.Add(workerThread);
}
while (true)
{
Console.WriteLine("I'm spinning... ");
Thread.Sleep(2000);
}
}
static void MakeSomeLoad()
{
for (int i = 0; i < 100000000; i++)
{
for (int j = 0; j < i; j++)
{
//uncomment the following line to increase the load
//Thread.Sleep(0);
StringBuilder sb = new StringBuilder();
sb.Append("hello world" + j);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
你的测试看起来很重.如果在一个进程中有16个线程,则GC将在该进程中运行更多,并且由于客户端GC不是并行的,因此会导致负载降低.即每个GC线程有16个垃圾生成线程.
另一方面,如果运行8个进程,每个进程有两个线程,则只有两个线程为每个GC线程生成垃圾,GC可以在这些进程之间并行工作.
如果您编写的测试产生的垃圾较少,并且直接使用更多的CPU,则可能会得到不同的结果.
(注意,这只是猜测,我没有运行你的测试,因为我只有一个双核CPU,不管你的结果如何)