Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.73/11: Рейтинг темы: голосов - 11, средняя оценка - 4.73
62 / 63 / 28
Регистрация: 10.01.2018
Сообщений: 360
.NET 4.x

Управляемый ThreadPool

28.03.2018, 12:02. Показов 2015. Ответов 5
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток! В образовательных целях пишу что-то, напоминающее ftp-сервер. Задумал реализовать многопоточность.
Мне бы мог подойти ThreadPool. Вот только меня не устраивает то, что, как я понял, он на 90% неуправляемый для программиста. То есть поток добавил в него и тот начинает жить своей жизнью. Если не прав поправьте, пожалуйста.
Мне же нужен механизм, который бы позволил управлять количеством одновременных подключений, но в то же время чтоб я мог их все завершить, без подавления исключения на каждом потоке(Операция ввода/вывода была прервана) и перезапуска приложения. Попытался написать свой, управляемый ThreadPool. Но результат нагрузки на процессор очень огорчил. Из 0-1% на 1 потоке загрузка ЦП выросла до 25-27%. Сервер, вроде как, неплохо работает, ну или по крайней мере я не смог вызвать ошибку. Но нужна полная оптимизация кода. Можете что-нибудь посоветовать?
Вот код моего "ThreadPool" с комментариями по поводу моих ожиданий относительно него
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
//старт
        public void Start(string ip, int port)
        {
            string url = "http://" + ip + ":" + port + "/";
            HostListener.Prefixes.Add(url);
            HostListener.Start(); //запуск прослушки
            MainThread = new Thread(new ThreadStart(ThreadController)); //чтоб не зависал UI
            MainThread.Start();
        }
 
        private static int ThreadLimit = 20; //количество подключений
 
        private int Reserve = 4; //запас места в Pool-е если вдруг там что-то будет не синхронизировано
 
        private Thread[] ThPool = new Thread[ThreadLimit]; //Pool
 
        private List<int> FreePlace = new List<int>(); //Индексы указывающие на свободное место в Pool-е
 
        ThreadsSupervisor TS; 
 
        private class ThreadsSupervisor //Наблюдатель за пулом
        {
            private Thread[] ThPool;
            private List<int> FrPlace;
            private Thread ScanThr;
            private bool Release = false;
 
            public void Watch(Thread[] thds, List<int> free)
            {
                ThPool = thds;
                FrPlace = free;
                Release = false;
                ScanThr = new Thread(new ThreadStart(Scaner)); //запускаем сканер
                ScanThr.Start();
            }
 
            public void Stop()
            {
                Release = true;
            }
 
            private void Scaner()
            {
                while (!Release)
                {
                    for (int i = 0; i < ThPool.Length; i++) //проходимся по Pool-у
                    {
                        //Если место не инициализировано или поток "мертв" 
                        //и Cписок индексов меньше чем количество потоков 
                        if ((ThPool[i]==null || !ThPool[i].IsAlive) && FrPlace.Count < ThreadLimit) 
                        {
                            FrPlace.Add(i); //Добавляем в список индекс "свободного пространства"
                        }
                    }
                }
            }
        }
 
        private void ThreadController()
        {
            TS = new ThreadsSupervisor();
            TS.Watch(ThPool,FreePlace);
 
            while (HostListener.IsListening)
            {
                Context = HostListener.GetContext();
 
                //Если количество свободных мест в Pool-е больше за "резерв"
                if (FreePlace.Count > Reserve)
                {
                    int index = FreePlace.Count - 1; //чтоб не получился рассинхрон между new, start, remove
                    ThPool[index] = new Thread(new ParameterizedThreadStart(RequesHandler));
                    ThPool[index].Start(Context.Request); 
                    FreePlace.Remove(index); //удаляем индекс из списка тк он уже занят
                }
                else
                {
                    Context.Response.ContentType = "text/html";
                    byte[] Temp = Encoding.UTF8.GetBytes("Сервер под высокой нагрузкой. Повторите операцию позже.");
                    Context.Response.ContentLength64 = Temp.Length;
                    Context.Response.OutputStream.Write(Temp, 0, Temp.Length);
                    Context.Response.Close();
                }
            }
        }
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
28.03.2018, 12:02
Ответы с готовыми решениями:

ThreadPool
Посоветовали мне использовать ThreadPool вместо Thread, но пока не понял, как его использовать. Если раньше: Thread myThread = new...

Закрытие ThreadPool
И снова здравствуйте. Есть оконное приложение, его структура: private void button1_Click(object sender, EventArgs e) ...

ThreadPool и BlockingCollection
Добрый день. Имеется многопоточное приложение, в одном потоке очередь заполняется сообщениями, в другом сообщения извлекаются и...

5
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
28.03.2018, 12:09
Цитата Сообщение от Sternman Посмотреть сообщение
он на 90% неуправляемый для программиста.
Управляемость какого вида интересует?

Цитата Сообщение от Sternman Посмотреть сообщение
поток добавил в него и тот начинает жить своей жизнью.
Это как?
Поток выполняет метод, который вы ему сказали выполнять.
У вас методы живут своей жизнью?

Цитата Сообщение от Sternman Посмотреть сообщение
Мне же нужен механизм, который бы позволил управлять количеством одновременных подключений
Не совсем понятно, какое отношение количество подключений имеют к пулу потоков.
Создайте список TcpClient/Socket/ЧтоВыИспользуете и будет готовый механизм управления имеющимися подключениями.

Цитата Сообщение от Sternman Посмотреть сообщение
но в то же время чтоб я мог их все завершить, без подавления исключения на каждом потоке(Операция ввода/вывода была прервана)
Не получится. Исключение при принудительном закрытии соединения придется обрабатывать.
Только опять не понятно, как завершение подключения относится к пулу потоков.
0
62 / 63 / 28
Регистрация: 10.01.2018
Сообщений: 360
28.03.2018, 12:37  [ТС]
Цитата Сообщение от kolorotur Посмотреть сообщение
Управляемость какого вида интересует?
Задать максимальное количество подключений, это есть в ThreadPool, и, как минимум, прерывать все потоки без перезапуска приложения, чисто "хотелка" и как бы не критична, но все таки лучше когда нажал кнопку стоп и старт. А не по крестику.
Цитата Сообщение от kolorotur Посмотреть сообщение
Поток выполняет метод, который вы ему сказали выполнять.
Он его выполняет, но я выключаю сервер и сразу же исключение тк поток пытается выполнить метод но канала с клиентом уже нету. Нужно сначала завершить потоки и только потом выключить сам listener.
Цитата Сообщение от kolorotur Посмотреть сообщение
какое отношение количество подключений имеют к пулу потоков.
В threadpool есть же возможность задать максимальное/минимальное количество потоков.
Цитата Сообщение от kolorotur Посмотреть сообщение
ЧтоВыИспользуете
HttpListener если это может как то помочь вопросу
Цитата Сообщение от kolorotur Посмотреть сообщение
Не получится
При одном же обычном потоке получается, оборвали поток выключили слушателя исключений нету.
Цитата Сообщение от kolorotur Посмотреть сообщение
не понятно, как завершение подключения относится к пулу потоков.
К стандартному вообще никакого, к тому который я пытался реализовать следующее: Перед остановкой слушателя пробегаемся по массиву с Thread, делаем, если нужно, Abort. Останавливаем HttpListener. Не получаем исключений

Добавлено через 15 минут
К стати, только заметил что в добавлении индекса есть баг, когда в список могут добавится одинаковые индексы. Но глобально на суть вопроса это не влияет.
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
28.03.2018, 12:52
Цитата Сообщение от Sternman Посмотреть сообщение
Задать максимальное количество подключений
А зачем для этого вообще как-то потоки использовать?
Сделайте ограничение на количество соединений в списке и всего делов.

Цитата Сообщение от Sternman Посмотреть сообщение
я выключаю сервер и сразу же исключение тк поток пытается выполнить метод но канала с клиентом уже нету.
Это может произойти и без вашего участия — например, если у клиента отключат электричество за неуплату, так что обрабатывать данную ситуацию придется в любом случае.
Ну а раз ее все равно придется обрабатывать, то почему бы там же и не учесть завершение работы с вашей стороны?

Цитата Сообщение от Sternman Посмотреть сообщение
Нужно сначала завершить потоки и только потом выключить сам listener.
Используйте для этого соответствующие конструкции. Например, CancellationToken.
Или вы планировали использовать метод Abort?

Цитата Сообщение от Sternman Посмотреть сообщение
В threadpool есть же возможность задать максимальное/минимальное количество потоков.
А зачем вообще количество потоков, равное количеству клиентов?
Вы планируете каждому клиенту выделать отдельный поток? 1000 клиентов — это 1000 потоков и 1ГБ оперативы только под стеки. Не жирно будет?
Особенно если учесть, что 99% времени клиенты ФТП-сервера будут проводить в режиме IO и эти потоки будут сидеть замороженными без дела.
Держите клиенты в обычном списке, а для того 1% времени, когда нужна локальная обработка, выполняйте ее в потоках пула путем использования асинхронной модели. Это приведет к тому, что пара десятков потоков пула у вас будет с легкостью обрабатывать сотни клиентов. Разумеется, свой пул для этого создавать не нужно — уже готовый работает просто отлично. Особенно с учетом специально имеющихся в нем потоков для обработки IO-завершений.

Цитата Сообщение от Sternman Посмотреть сообщение
При одном же обычном потоке получается, оборвали поток выключили слушателя исключений нету.
Это так кажется только при первом рассмотрении самого простого случая (вы же Abort используете для обрыва потока, да?).
Уничтожение потока вызовом Abort — это самовольно загнать свое же приложение в состояние полной неопределенности, т.к. поток уничтожается в прямом смысле на следующей же инструкции. Это значит, что поток может быть уничтожен на пол-пути вызова конструктора, выделения критичного ресурса, замыкания ограниченного ресурса ОС и т.д., превращая приложение в минное поле, когда оно может бомбануть в любой момент из-за того, что вон тот вон объект не закончил инициализацию из-за прерванного потока и теперь пытается лезть куда-нибудь в защищенную память.

Цитата Сообщение от Sternman Посмотреть сообщение
делаем, если нужно, Abort.
Ну, собственно.
2
62 / 63 / 28
Регистрация: 10.01.2018
Сообщений: 360
28.03.2018, 13:18  [ТС]
Цитата Сообщение от kolorotur Посмотреть сообщение
Сделайте ограничение на количество соединений в списке
Можно поподробней где это делать? потому что на данный момент у меня нету списка подключений
Цитата Сообщение от kolorotur Посмотреть сообщение
у клиента отключат электричество за неуплату, так что обрабатывать данную ситуацию придется в любом случае.
Не придется
C#
1
HostListener.IgnoreWriteExceptions = true;
Цитата Сообщение от kolorotur Посмотреть сообщение
1000 клиентов
Не получится, сервер можно запустить только на интерфейсе Wi-Fi сети. То есть больше 100 одновременных подключений скорее всего недостижимый результат. Поэтому экономить на ресурсах, при малой нагрузке, смысла нету, вроде как. Хотя если честно я не смог в домашних условиях загрузить даже 1 поток, но думаю, что человек 5 смогли бы при загрузке/скачивании файлов.
Цитата Сообщение от kolorotur Посмотреть сообщение
объект не закончил инициализацию из-за прерванного потока и теперь пытается лезть куда-нибудь в защищенную память.
не знал, что такое возможно.
Цитата Сообщение от kolorotur Посмотреть сообщение
Держите клиенты в обычном списке
Не могли бы вы показать как это делать на примере HttpListener, или дать ключевые слова для поиска?
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
28.03.2018, 13:26
Лучший ответ Сообщение было отмечено Sternman как решение

Решение

Цитата Сообщение от Sternman Посмотреть сообщение
Можно поподробней где это делать?
Цитата Сообщение от Sternman Посмотреть сообщение
Не могли бы вы показать как это делать на примере HttpListener, или дать ключевые слова для поиска?
Там, где ваш Listener принимает подключения.
При подключении добавляйте клиента в список (класс List<T>), если список достиг определенного количества, вместо добавления сразу закрывайте соединение.
Отключившихся/отвалившихся клиентов удаляйте из списка.

Цитата Сообщение от Sternman Посмотреть сообщение
Не придется
То есть раз подключившись, клиент у вас всегда считается подключенным, даже если по факту он отвалился?
Первый же клиент с нестабильным соединением повалит ваш сервер.

Цитата Сообщение от Sternman Посмотреть сообщение
больше 100 одновременных подключений скорее всего недостижимый результат.
С чего это?
Глянул на наш корпоративный Wi-Fi в офисе — на данный момент свыше полутора тысяч активных подключений — у каждого сотрудника в кармане мобилка, а то и две.
Или вы о чем-то другом?
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
28.03.2018, 13:26
Помогаю со студенческими работами здесь

Работа с потоками ThreadPool
Условие . Создавать потоки необходимо при помощи класса ThreadPool (для нечетных вариантов). Для реализации следует использовать...

Сканирование портов в несколько потоков с помощью ThreadPool
Мне необходимо создать приложение в котором вводится определенное количество потоков которые сканируют порты. Как создать? ...

Потоки, мультипоточность Task or Async/Await or ThreadPool?
Здравствуйте форумчане. Я очень нуждаюсь в вашей помощи. Я реализовываю парсер с одного довольно популярного сайта занятости и...

Как в ThreadPool проверить, что все потоки завершены
Как можно проверить, что все потоки завершили свою работу в ThreadPool, а после выполнить какое-нибудь действие?

Ограниченное количество одновременно работающих потоков без ThreadPool
К делу. Так это работает в ThreadPool ThreadPool.QueueUserWorkItem(clientObject.Process); ThreadPool.SetMaxThreads(3, 3); Как это...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru