Замедление при создании объектов с большим количеством потоков

, я делаю проект, который порождает несколько сотен потоков. Все эти потоки находятся в состоянии" сна "(они заблокированы на объекте Monitor). Я заметил, что если я увеличиваю количество «спящих» потоков, программа сильно замедляется. "Забавно" то, что при взгляде на диспетчер задач кажется, что чем больше потоков, тем свободнее процессор. Я сузил проблему до создания объекта.

Кто-нибудь может мне это объяснить?

Я изготовил небольшой образец для проверки. Это консольная программа. Он создает поток для каждого процессора и измеряет его скорость с помощью простого теста («новый объект ()»). Нет, «новый объект ()» не убирается (попробуйте, если вы мне не доверяете). Основной поток показывает скорость каждого потока. При нажатии CTRL-C программа порождает 50 «спящих» потоков. Замедление начинается всего с 50 потоков. Около 250 шт. В диспетчере задач очень заметно, что ЦП используется не на 100% (в моем случае это 82%).

Я пробовал три метода блокировки «спящего» потока: Thread.CurrentThread.Suspend () (плохо, плохо, я знаю :-)), блокировку уже заблокированного объекта и Thread.Sleep (Timeout. Бесконечный). Это то же самое. Если я прокомментирую строку новым Object () и заменю ее на Math.Sqrt (или ничего), проблемы не будет. Скорость не меняется с количеством потоков. Sqrt (или ни с чем) проблемы нет. Скорость не меняется с количеством потоков. Sqrt (или ни с чем) проблемы нет. Скорость не меняется с количеством потоков. Может кто нибудь еще это проверить? Кто-нибудь знает, где находится бутылочное горлышко?

А ... вы должны протестировать его в режиме выпуска БЕЗ запуска из Visual Studio. Я использую XP sp3 на двухпроцессорном (без HT). Я тестировал его с .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}", i, newCol);
                }
            }
        }
    }
}
9
задан Charles 10 September 2011 в 14:54
поделиться