Потенциал Threading в FX 1.1 и FX 2.0
От: e-Shaman http://smekalka.ru
Дата: 28.11.06 23:45
Оценка:
Возможно я не впервые поднимаю подобную тему, но дело вот какое... Я заметил один очень удививший меня косяк в Threading-е от .NET Framework 2.0. Мне очень важны ваши, коллеги, комментарии этой ситуации. Далее подробности...

Предыстория
Так или иначе мне захотелось узнать, сколько потоков нараз может создать-запустить процесс, работающий под .NET Framework. Для этого я написал незамысловатую программку, которая создаёт и запускает потоки до упора — до тех пор, пока не возникнет какая-либо исключительная ситуация. Условия были взяты за идеальные, поэтому сам поток никакой логикой я не стал нагружать и лишь только инкрементировал в нём счётчик запустившихся потоков, а затем ставил на минуту в ожидание. Код программки получился вот такой:

using System;
using System.Threading;

class ThreadingStressTest
{
    private static volatile int threadCount = 0;

    [STAThread]
    static void Main(string[] args)
    {
        Console.WriteLine("Starting threading stress test...");
        DateTime startTime = DateTime.Now;
        DateTime finishTime;

        try
        {
            while (true)
            {
                Thread thread = new Thread(new ThreadStart(ThreadProc));
                thread.Start();
            }
        }
        catch (Exception e)
        {
            finishTime = DateTime.Now;
            Console.WriteLine("Finished by {0} exception.", e.GetType().ToString());
        }

        Console.WriteLine("Threads created: {0}", threadCount);
        Console.WriteLine("Time elapsed: {0}", finishTime - startTime);

        Console.Write("Press <Enter>...");
        Console.Read();
    }

    private static void ThreadProc()
    {
        threadCount++;
        Thread.Sleep(60000);
    }
}


Эту программку я откомпилировал под фреймворки версий 1.1 и 2.0 (прижелании бинарники можно найти здесь).

Собственно история
Эти программки я прогнал не только на нескольких доступных мне системах, но и попросил сделать то же самое нескольких своих приятелей. И собранные в итоге сведения меня очень-очень поразили.

Для фреймворка 1.1 количество созданных и запущенных потоков составило в среднем примерно 1950, вне зависимости от системы (Windows 2000/XP/Vista) и конфигурации аппарата. Мощность железки влияла лишь на время выполнения всего этого цикла, и оно в любом случае было крайне мало. Во всех случаях всплеск по общему потреблению оперативной памяти составил примерно 50 Мб, и на работу системы ощутимого влияния выполнение этого процесса не оказывало. Результаты, надо сказать, достаточно неплохие.

Но результаты, полученные для фреймворка 2.0, сложно назвать утешительными. Для него количество потоков в большинстве случаев получилось примерно 1500, но в целом ряде случаев получались и такие результаты, как ~800 потоков или ~1900 потоков. Зависело это напрямую от количества доступной оперативной памяти. Время выполнения цикла в большинстве случаев (при количестве 1500 потоков) было в два раза больше, чем для FX 1.1. Но самое поразительное то, что в момент выполнения процесса всплеск по общему потреблению памяти был просто колоссальным. Соответствующий график в Task Manager уходил в потолок, и собственно по достижении этого потолка цикл и завершался. Практически во всех случаях система выдавала сообщение, что память всё. Кроме того исполнение этого процесса на не шибко мощных машинах просто переклинивало систему, и её отпускало лишь по завершению программы, когда все потоки выходили из ожидания и завершались. Самое интересно, что исключением в этой ситуации стала Windows Vista, под которой честно выделялись ~1450 потоков, а всплеск по общему потреблению памяти был даже чуть меньше, чем для FX 1.1, и составил примерно 30 Мб.

В итоге полученные результаты отбили у меня желание портировать под FX 2.0 разработанный мною процессинговый сервис, успешно работавший на высоких нагрузках под FX 1.1.
Re: Потенциал Threading в FX 1.1 и FX 2.0
От: Красин Россия  
Дата: 29.11.06 00:05
Оценка:
ES>Но результаты, полученные для фреймворка 2.0, сложно назвать утешительными. Для него количество потоков в большинстве случаев получилось примерно 1500, но в целом ряде случаев получались и такие результаты, как ~800 потоков или ~1900 потоков.

Windows 2003 64 bit, .net 2.0, 2 Gb RAM:
Threads created: 3362
Time elapsed: 00:00:01.0312500
Re[2]: Потенциал Threading в FX 1.1 и FX 2.0
От: Красин Россия  
Дата: 29.11.06 00:11
Оценка:
С учетом, что в системе в районе 4 Гб виртуальной памяти, получается примерно по 1.5 Мб на поток. Фактически, это размер стека, который выделяется для этого потока.
Потенциал Threading в FX 1.1 и FX 2.0
От: Аноним  
Дата: 29.11.06 01:41
Оценка:
в 2.0 больше удобства и больше тормазов , а ты не пробывал уменьшить стек для создаваемого потока? или оптимизировать архитектуру, по всей видимости у тебя приложение с блокирующими сокетами, попробуй покопать в сторону асинхронии, или в пулы потоков.
--------------
Любое удобство идет за счет мегагерцеф! : {<b>1</b>, <b>2</b>, <b>3</b>, 4}


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re: Потенциал Threading в FX 1.1 и FX 2.0
От: desco США http://v2matveev.blogspot.com
Дата: 29.11.06 06:15
Оценка:
Здравствуйте, e-Shaman, Вы писали:

Windows XP, 2 GB RAM, 2.0

// стандартный размер стека потока (1 MB)

Starting threading stress test...
Finished by System.Threading.ThreadStartException exception.
Threads created: 1671
Time elapsed: 00:00:00.4062500


// размер стека потока 512 KB

Starting threading stress test...
Finished by System.Threading.ThreadStartException exception.
Threads created: 3300
Time elapsed: 00:00:00.9843750


// размер стека потока 256 KB

Starting threading stress test...
Finished by System.Threading.ThreadStartException exception.
Threads created: 6449
Time elapsed: 00:00:03.3125000

Re: Потенциал Threading в FX 1.1 и FX 2.0
От: adontz Грузия http://adontz.wordpress.com/
Дата: 29.11.06 06:33
Оценка: -1
Здравствуйте, e-Shaman, Вы писали:

Абсолютно идиотский тест. Количество потоков не должно превышать количество физических процессоров больше чем в два раза. Серверный софт с с более чем 4-5 потоками на процессор в топку.
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[3]: Потенциал Threading в FX 1.1 и FX 2.0
От: e-Shaman http://smekalka.ru
Дата: 29.11.06 06:38
Оценка:
А для FX 1.1 какие расклады на этой системе?
Re[2]: Потенциал Threading в FX 1.1 и FX 2.0
От: e-Shaman http://smekalka.ru
Дата: 29.11.06 06:44
Оценка:
"Серверный софт" тот самый как раз ThreadPool использует
А тест чисто на оценку потенциальных возможноестей... Ясное дело, что если в потоке будет более-менее навороченная логика, то тупо создавать-запускать потоки с нею не дело.
Re: Потенциал Threading в FX 1.1 и FX 2.0
От: Константин Л. Франция  
Дата: 29.11.06 09:27
Оценка:
Здравствуйте, e-Shaman, Вы писали:

а кому это 800 потоков мало?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Потенциал Threading в FX 1.1 и FX 2.0
От: e-Shaman http://smekalka.ru
Дата: 29.11.06 10:28
Оценка:
Да дело-то в принципе не в количестве даже, а в том, как FX 2.0 при этом память кушает. А кушает он её бессовестно жадно...
Re: Потенциал Threading в FX 1.1 и FX 2.0
От: Mab Россия http://shade.msu.ru/~mab
Дата: 29.11.06 10:38
Оценка: +3
Здравствуйте, e-Shaman, Вы писали:

ES>В итоге полученные результаты отбили у меня желание портировать под FX 2.0 разработанный мною процессинговый сервис, успешно работавший на высоких нагрузках под FX 1.1.

Довольно странное решение -- использовать в сервере, где возникают выскокие нагрузки, сотни и даже тысячи потоков. Это же не fibers, threads банально не предназначены для подобного использвания. А уж сколько там памяти кто кушает -- это дело вторичное, ошибка была допушена раньше при дизайне системы.
Re[2]: Потенциал Threading в FX 1.1 и FX 2.0
От: e-Shaman http://smekalka.ru
Дата: 29.11.06 11:16
Оценка:
Уххх! Да не использует мой сервер этот подход! Он использует гибридный вариант на основе ThreadPool в качестве основной очереди для массового запуска потоков, и отдельных Thread-ов как дополнительных ресурсов для исполнения задач с очень большим временем исполнения, чтобы не захламлять ими ThreadPool.

Идея провести тот тест возникла из чисто спортивного интереса. Это вот как прыжки в высоту с шестом или как какой-нибудь Street Racing, когда люди которые, в обыденной ситуации передвигаются пешком или на авто в более-менее вменяемом режиме, хотят раскрыть свой потенциал или потенциал движка своего автомобиля и т.п. Слово "потенциал" и тут, и в случае с Threading является колючевым. Давайте тогда будем называть наш случай Thread Racing...
Re[3]: Потенциал Threading в FX 1.1 и FX 2.0
От: Mab Россия http://shade.msu.ru/~mab
Дата: 29.11.06 11:33
Оценка:
Здравствуйте, e-Shaman, Вы писали:

ES>Уххх! Да не использует мой сервер этот подход! Он использует гибридный вариант на основе ThreadPool в качестве основной очереди для массового запуска потоков, и отдельных Thread-ов как дополнительных ресурсов для исполнения задач с очень большим временем исполнения, чтобы не захламлять ими ThreadPool.

Тогда не вижу проблем с портабельностью.

ES>Идея провести тот тест возникла из чисто спортивного интереса. Это вот как прыжки в высоту с шестом или как какой-нибудь Street Racing, когда люди которые, в обыденной ситуации передвигаются пешком или на авто в более-менее вменяемом режиме, хотят раскрыть свой потенциал или потенциал движка своего автомобиля и т.п.

Мое ИМХО -- это примерно как устраивать соревнование, в какой OS можно больше окон одновременно создать. Так сказать, чтобы раскрыть потенциал User32 Практическая польза близка к нулю.
Re[4]: Потенциал Threading в FX 1.1 и FX 2.0
От: e-Shaman http://smekalka.ru
Дата: 29.11.06 11:53
Оценка:
Ну почему же?..

Практический вывод тут как минимум такой — FX 1.1 создаёт и запускает потоки не только быстрее, чем FX 2.0, но и аккуратнее, о чём свидетельствует примерно одинаковое количество максимума этих потоков для разных систем и затрачиваемый при этом объём оперативной памяти.

Поэтому если говорить про стабильность и надёжность работы севрверного решения на основе .NET Framework, то тут всё скорее в пользу старого доброго 1.1.

Да, я полагаю, можно портировать мой сервис на 2.0, что я возможно и сделаю когда-нибудь, но пока овчинка не стоит выделки, поэтому не вижу плюсов за то, чтобы это делать сейчас, или если сейчас, то запускать такое решение в production, когда такая картинка по нагрузочным характеристикам Threading-а.
Re[5]: Потенциал Threading в FX 1.1 и FX 2.0
От: Mab Россия http://shade.msu.ru/~mab
Дата: 29.11.06 12:19
Оценка:
Здравствуйте, e-Shaman, Вы писали:

Ладно, похоже, что спорить быссмысленно, и каждый останется при своем мнении. Естественно, если что-то уже хорошо работает, то нет никакой необходимостьи его ломать и куда-то переносить. Но делать выводы о надежности чего-либо исходя из столь странных и нетипичных тестов я бы не стал
Re[5]: Потенциал Threading в FX 1.1 и FX 2.0
От: mrozov  
Дата: 29.11.06 12:33
Оценка:
Здравствуйте, e-Shaman, Вы писали:

ES>Ну почему же?..


ES>Практический вывод тут как минимум такой — FX 1.1 создаёт и запускает потоки не только быстрее, чем FX 2.0, но и аккуратнее, о чём свидетельствует примерно одинаковое количество максимума этих потоков для разных систем и затрачиваемый при этом объём оперативной памяти.


Мягко говоря, странный вывод.
Напоминает логику тех, кто измеряет качество операционной системы размером ее ядра в памяти...

Тебе вроде абсолютно конкретно ткнули, что конкретно измеряет твой тест. А измеряет он размер стека, выделяемого потоку по-умолчанию.
Тебе нужно создать 10000 потоков? Уменьшай размер стека. Тебе это не нужно? Правильно, никому не нужно.

Скажи на милость, а каким образом твой тест доказывает, что если потоку выделить меньший размер стека, то он будет работать "не только быстрее, но и аккуратнее"? Я так думаю, что все в точности наоборот. Поэтому во втором FW это поведение и изменили.
Re[6]: Потенциал Threading в FX 1.1 и FX 2.0
От: Jericho113 Украина  
Дата: 29.11.06 12:40
Оценка:
Здравствуйте, Mab, Вы писали:


Mab>Ладно, похоже, что спорить быссмысленно, и каждый останется при своем мнении. Естественно, если что-то уже хорошо работает, то нет никакой необходимостьи его ломать и куда-то переносить. Но делать выводы о надежности чего-либо исходя из столь странных и нетипичных тестов я бы не стал


Ок. если по вашему мнению этот тест является "странным и нетипичным",
тогда приведите пожалуйста простой стресс тест как можно сравнить .NET 1.1 и 2.0 в
плане многопоточности и потребляемой при этом памяти/загрузки CPU.
Я думаю многим будет интересно.
NetDigitally yours ....
Re[6]: Потенциал Threading в FX 1.1 и FX 2.0
От: e-Shaman http://smekalka.ru
Дата: 29.11.06 13:12
Оценка:
Бррр
Я вообще как-то и не затрагивал особо тему размера стека, поэтому с этим в этой веточке, наверное, не ко мне...

Кстати, у вас есть какое-то определённое представление о том, как это всё работает, как функционирует это самое поведение?
Re[7]: Потенциал Threading в FX 1.1 и FX 2.0
От: mrozov  
Дата: 29.11.06 14:07
Оценка: 2 (1)
Здравствуйте, e-Shaman, Вы писали:

ES>Бррр

ES>Я вообще как-то и не затрагивал особо тему размера стека, поэтому с этим в этой веточке, наверное, не ко мне...

ES>Кстати, у вас есть какое-то определённое представление о том, как это всё работает, как функционирует это самое поведение?


Память выжирается и все падает в зависимости от размера стека. Твой тест, по сути, проверяет, какой объем памяти под это дело выделяется в разных версиях фреймворка. Не больше — не меньше.

Т.е. из твоего теста можно сделать только такой вывод, что теперь размер стека по-умолчанию увеличен. И никакого другого.
Цитирую MSDN:

The ability to set a thread's stack size is not new to Win32® developers, as the CreateThread function exposes that capability, but it is new to managed threads with the .NET Framework 2.0. Just because the option is exposed doesn't mean you should use it, though. The default stack size of 1MB should be appropriate for almost any application you're developing. If it's not, chances are you have a bug or poor design in your code. That said, there are valid circumstances where you might want to change the stack size.

An easy way to see the effect of this parameter is to create and start as many threads as you can. Suppose you have two gigabytes of virtual address space. If all of that space is available for thread creation and if each thread reserves 1MB of memory, you should be able to create around 2000 threads. Figure 2 shows a simple test harness for counting the number of threads that can be created and started with a specific stack size. Sure enough, calling it three times with starting stack sizes of 512KB, 1MB, and 2MB, respectively, yields the following output:

After 3828 threads: OutOfMemoryException
After 1917 threads: OutOfMemoryException
After 956 threads: OutOfMemoryException
Re[7]: Потенциал Threading в FX 1.1 и FX 2.0
От: Mab Россия http://shade.msu.ru/~mab
Дата: 29.11.06 17:32
Оценка:
Здравствуйте, Jericho113, Вы писали:

J>Я думаю многим будет интересно.

Наверное будет, но только это сложная задача, за которую я не собираюсь браться. Даже выработать объективный параметр эффективности тут непросто.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.