C# 核心和我能产生的线程数之间的关系
我有一个英特尔四核处理器 如果我要开发一个只在我的机器上使用的Winforms应用程序(我使用C#btw),我可以生成多少线程C# 核心和我能产生的线程数之间的关系,c#,multithreading,concurrency,hardware,C#,Multithreading,Concurrency,Hardware,我有一个英特尔四核处理器 如果我要开发一个只在我的机器上使用的Winforms应用程序(我使用C#btw),我可以生成多少线程 内核与我在任何时候可以运行的最大线程数之间是否存在某种关联?我需要知道在任何时候有多少线程在运行吗?如果是的话,这是可能的吗?(我知道有像最小和最大线程这样的属性)?这是否取决于线程池(此池中的最大线程数是否更改?)。这是本文/线程的C#部分。这一切都取决于,如果线程100%处于活动状态(而不是等待IO),那么每个CPU拥有超过1个线程就没有什么意义了。但是,除非执行复
内核与我在任何时候可以运行的最大线程数之间是否存在某种关联?我需要知道在任何时候有多少线程在运行吗?如果是的话,这是可能的吗?(我知道有像最小和最大线程这样的属性)?这是否取决于线程池(此池中的最大线程数是否更改?)。这是本文/线程的C#部分。这一切都取决于,如果线程100%处于活动状态(而不是等待IO),那么每个CPU拥有超过1个线程就没有什么意义了。但是,除非执行复杂的数值计算,否则这种情况很少发生 .Nets线程池具有: 线程池的默认大小为 每个可用线程250个工作线程 处理器和1000 I/O完成 线程 所以,我想说,除了以下几点,几乎没有人能给你推荐:
- 测量李>
在某些时候,当你添加更多线程时,由于上下文切换和同步,东西会变慢。而线程和核心之间的相关性不强(线程真正并发执行的唯一方法是在不同的内核上运行,但这些知识的价值比您想象的要小),真正的工作是由操作系统调度程序完成的,在本例中是Windows中的线程调度程序 至于您可以创建多少线程,这将因系统而异。
ThreadPool
类对生成您自己的线程没有任何限制;它有一个内部管理的线程池。这些是您在检查ThreadPool
类的属性时可以看到的值然而,这并不是说你应该产生无限的线程;最终操作系统在线程之间切换的时间将比实际允许线程运行的时间要长。通过基准测试,找出适合你的应用程序的线程数量
你到底想干什么
我可以生成多少线程
哇,哇,哇,比你想要的要多(数百倍或数千倍),以获得最佳吞吐量
我知道的每线程限制(在Windows上)是:
- 16位线程ID
- 为用户空间堆栈分配4-8KB(通常更多)
- 不可分页的内核空间上下文和堆栈,大约16KB
threads = 2 * (cpu cores + active disk spindles)
最佳数量通常在其中的两倍以内。理论上,所需的线程与cpu核心成比例(出于明显的原因),但也有一些线程会在磁盘I/O上阻塞。乘以2可以让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()
)
使用系统;
使用System.Linq;
使用系统线程;
命名空间GeneralTestApplication
{
班级计划
{
私有静态void Main()
{
WriteLine(“输入要启动的线程数”);
而(!Int32.TryParse(Console.ReadLine(),out Program.numberThreads)){
Program.counters=new Int64[Program.numberThreads];
WriteLine(“启动{0}个线程。”,Program.numberThreads);
对于(Int32 threadNumber=0;threadNumberc>0));
Console.ReadLine();
}
私有静态Int32 numberThreads=0;
私有静态Int64[]计数器=null;
专用静态只读ManualResetEvent ManualResetEvent=新的ManualResetEvent(错误);
私有静态可变布尔停止=false;
公共静态void ThreadMethod(对象参数)
{
Int32 threadNumber=(Int32)参数;
Program.manualResetEvent.WaitOne();
而(!Program.stop)
{
程序计数器[threadNumber]++;
//取消注释以模拟繁重的工作。
睡眠(10);
}
}
}
}
您必须测量。也就是说,对于N个核,我通常会得到最好的结果b
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);
}
}
}
}