c# – 使用多个线程创建对象时减速

c# – 使用多个线程创建对象时减速,第1张

概述我正在做一个产生数百个线程的项目.所有这些线程处于“睡眠”状态(它们被锁定在Monitor对象上).我注意到,如果我增加“睡眠”线程的数量,程序会减慢很多. “有趣的”事情是看任务管理器,似乎线程数越多,处理器的空闲就越多.我将问题缩小到对象创建. 有人可以向我解释吗? 我制作了一个小样本来测试它.这是一个控制台程序.它为每个处理器创建一个线程,并通过简单的测试(“新的Object()”)来测量它 我正在做一个产生数百个线程的项目.所有这些线程处于“睡眠”状态(它们被锁定在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);                }            }        }    }}
解决方法 我的猜测是,垃圾收集需要线程之间的一定程度的合作 – 有些东西需要检查它们是否被暂停,或者要求他们暂停自己并等待它发生等(即使他们被暂停,它不得不告诉他们不要醒来!)

当然,这描述了一个“停止世界”的垃圾收集器.我相信至少有两个或三个不同的GC实现方式在并行性方面有所不同,但我怀疑所有这些都将在获得线程合作方面做一些工作.

总结

以上是内存溢出为你收集整理的c# – 使用多个线程创建对象时减速全部内容,希望文章能够帮你解决c# – 使用多个线程创建对象时减速所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1260820.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-08
下一篇 2022-06-08

发表评论

登录后才能评论

评论列表(0条)

保存