C# 创建具有多线程的对象时速度减慢

C# 创建具有多线程的对象时速度减慢,c#,.net,multithreading,performance,asynchronous,C#,.net,Multithreading,Performance,Asynchronous,我正在做一个产生数百个线程的项目。所有这些线程都处于“睡眠”状态(它们被锁定在监视器对象上)。我已经注意到,如果我增加“睡眠”线程的数量,程序会非常慢。“有趣的”是,在任务管理器中,线程数越多,处理器就越空闲。我已将问题缩小到对象创建 有人能给我解释一下吗 我制作了一个小样本来测试它。这是一个控制台程序。它为每个处理器创建一个线程,并通过一个简单的测试(一个“newobject()”)来测量它的速度。不,“new Object()”没有被抖动掉(如果你不信任我,试试看)。主线程显示每个线程的速度

我正在做一个产生数百个线程的项目。所有这些线程都处于“睡眠”状态(它们被锁定在监视器对象上)。我已经注意到,如果我增加“睡眠”线程的数量,程序会非常慢。“有趣的”是,在任务管理器中,线程数越多,处理器就越空闲。我已将问题缩小到对象创建

有人能给我解释一下吗

我制作了一个小样本来测试它。这是一个控制台程序。它为每个处理器创建一个线程,并通过一个简单的测试(一个“newobject()”)来测量它的速度。不,“new Object()”没有被抖动掉(如果你不信任我,试试看)。主线程显示每个线程的速度。按CTRL-C,程序生成50个“休眠”线程。减速从50个线程开始。大约有250台,在任务管理器上很明显CPU的使用率不是100%(我的是82%)

我尝试了三种锁定“睡眠”线程的方法:thread.CurrentThread.Suspend()(坏,坏,我知道:-))、对已锁定对象的锁定和thread.Sleep(Timeout.Infinite)。都一样。如果我用new Object()注释该行,并用Math.Sqrt(或不使用任何内容)替换它,则问题不存在。速度不随线程数的变化而变化。 其他人能检查一下吗?有人知道瓶颈在哪里吗

啊。。。您应该在发布模式下测试它,而不必从VisualStudio启动它。 我在双处理器(无HT)上使用XP sp3。我已经用.NET3.5和4.0对它进行了测试(以测试不同的框架运行时)

名称空间测试速度
{
使用制度;
使用System.Collections.Generic;
使用系统线程;
班级计划
{
私有常量long ticksInSec=10000000;
专用常量long ticksims=ticksInSec/1000;
私有常量int threadsTime=50;
private const int stackSizeBytes=256*1024;
私有常量int waitTimeMs=1000;
私有静态列表收集=新列表();
私有静态int[]objsCreated;
静态void Main(字符串[]参数)
{
objsCreated=newint[Environment.ProcessorCount];
Monitor.Enter(objsCreated);
for(int i=0;i
{
if(e.SpecialKey!=控制台SpecialKey.ControlC)
{
返回;
}
对于(int i=0;i
{
/*这同样适用于永久锁定线程的所有三种“方法”*/
//Thread.CurrentThread.Suspend();
//Thread.Sleep(Timeout.Infinite);
锁(objsCreated){}
},stackSizeBytes)。开始();
联锁增量(参考numThreads);
}
e、 取消=真;
};
while(true)
{
线程睡眠(waitTimeMs);
控制台。设置光标位置(0,1);
DateTime now=DateTime.UtcNow;
长滴答声=(现在-最后)。滴答声;
WriteLine(“睡眠了{0}毫秒”,滴答声/滴答声);
Thread.MemoryBarrier();
for(int i=0;icollects.Count)
{
收集。添加(0);
}
for(int i=0;i
我的猜测是,问题在于垃圾收集需要线程之间一定程度的合作——要么需要检查它们是否都已挂起,要么要求它们挂起并等待它发生,等等(即使它们已挂起,它也必须告诉它们不要醒来!)

当然,这描述了一个“停止世界”垃圾收集器。我相信至少有两到三种不同的GC实现在并行性的细节上有所不同。。。但我怀疑,他们所有人都将有一些工作要做,以获得第三次世界大战
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}", i, newCol);
                }
            }
        }
    }
}
Unknown exception - code e0434f4e (first chance)
0118f010 5f3674da 00000000 00000000 83e36f53 KERNEL32!SuspendThread
0118f064 5f28c51d 00000000 83e36e63 00000000 mscorwks!Thread::SysSuspendForGC+0x2b0 (FPO: [Non-Fpo])
0118f154 5f28a83d 00000001 00000000 00000000 mscorwks!WKS::GCHeap::SuspendEE+0x194 (FPO: [Non-Fpo])
0118f17c 5f28c78c 00000000 00000000 0000000c mscorwks!WKS::GCHeap::GarbageCollectGeneration+0x136 (FPO: [Non-Fpo])
0118f208 5f28a0d3 002a43b0 0000000c 00000000 mscorwks!WKS::gc_heap::try_allocate_more_space+0x15a (FPO: [Non-Fpo])
0118f21c 5f28a16e 002a43b0 0000000c 00000000 mscorwks!WKS::gc_heap::allocate_more_space+0x11 (FPO: [Non-Fpo])
0118f23c 5f202341 002a43b0 0000000c 00000000 mscorwks!WKS::GCHeap::Alloc+0x3b (FPO: [Non-Fpo])
0118f258 5f209721 0000000c 00000000 00000000 mscorwks!Alloc+0x60 (FPO: [Non-Fpo])
0118f298 5f2097e6 5e2d078c 83e36c0b 00000000 mscorwks!FastAllocateObject+0x38 (FPO: [Non-Fpo])