我正在做一个产生数百个线程的项目.所有这些线程处于“睡眠”状态(它们被锁定在Monitor对象上).我注意到,如果我增加“睡眠”线程的数量,程序会减慢很多. “有趣的”事情是看任务管理器,似乎线程数越多,处理器的空闲就越多.我将问题缩小到对象创建.
有人可以向我解释吗?
我制作了一个小样本来测试它.这是一个控制台程序.它为每个处理器创建一个线程,并通过简单的测试(“新的Object()”)来测量它的速度.不,“新的Object()”没有被关闭(如果你不信任我的话).主线程显示每个线程的速度.按CTRL-C,程序产生50个“睡眠”线程.减速开始只有50个线程.大约有250个,在任务管理器上非常明显,cpu不是100%使用(在我的这是82%).
我已经尝试了三种锁定“睡眠”线程的方法:Thread.CurrentThread.Suspend()(坏,坏,我知道:-)),已经锁定的对象和Thread.Sleep(Timeout.Infinite)上的锁定.一样的.如果我用新的Object()对行进行评论,并用Math.Sqrt(或者没有)替换它,则不存在问题.速度不随线程数而变化.
有人可以检查吗?有谁知道瓶颈在哪里?
啊,你应该在发布模式下测试它,不要从Visual Studio启动它.
我在双处理器(没有HT)使用XP sp3.我已经使用.NET 3.5和4.0进行了测试(以测试不同的框架运行时间)
namespace TestSpeed { using System; using System.Collections.Generic; using System.Threading; class Program { private const long ticksInSec = 10000000; private const long ticksInMs = ticksInSec / 1000; private const int threadsTime = 50; private const int stackSizeBytes = 256 * 1024; private const int waitTimeMs = 1000; private static List<int> collects = new List<int>(); private static int[] objsCreated; static void Main(string[] args) { objsCreated = new int[Environment.ProcessorCount]; Monitor.Enter(objsCreated); for (int i = 0; i < objsCreated.Length; i++) { new Thread(Worker).Start(i); } int[] oldCount = new int[objsCreated.Length]; DateTime last = DateTime.UtcNow; Console.Clear(); int numThreads = 0; Console.WriteLine("Press Ctrl-C to generate {0} sleeping threads,Ctrl-Break to end.",threadsTime); Console.CancelKeyPress += (sender,e) => { if (e.SpecialKey != ConsoleSpecialKey.ControlC) { return; } for (int i = 0; i < threadsTime; i++) { new Thread(() => { /* The same for all the three "ways" to lock forever a thread */ //Thread.CurrentThread.Suspend(); //Thread.Sleep(Timeout.Infinite); lock (objsCreated) { } },stackSizeBytes).Start(); Interlocked.Increment(ref numThreads); } e.Cancel = true; }; while (true) { Thread.Sleep(waitTimeMs); Console.SetCursorPosition(0,1); DateTime now = DateTime.UtcNow; long ticks = (now - last).Ticks; Console.WriteLine("Slept for {0}ms",ticks / ticksInMs); Thread.MemoryBarrier(); for (int i = 0; i < objsCreated.Length; i++) { int count = objsCreated[i]; Console.WriteLine("{0} [{1} Threads]: {2}/sec ",i,numThreads,((long)(count - oldCount[i])) * ticksInSec / ticks); oldCount[i] = count; } Console.WriteLine(); CheckCollects(); last = now; } } private static void Worker(object obj) { int ix = (int)obj; while (true) { /* First and second are slowed by threads,third,fourth,fifth and "nothing" aren't*/ new Object(); //if (new Object().Equals(null)) return; //Math.Sqrt(objsCreated[ix]); //if (Math.Sqrt(objsCreated[ix]) < 0) return; //Interlocked.Add(ref objsCreated[ix],0); Interlocked.Increment(ref objsCreated[ix]); } } private static void CheckCollects() { int newMax = GC.MaxGeneration; while (newMax > collects.Count) { collects.Add(0); } for (int i = 0; i < collects.Count; i++) { int newCol = GC.CollectionCount(i); if (newCol != collects[i]) { collects[i] = newCol; Console.WriteLine("Collect gen {0}: {1}",newCol); } } } } }