![]() |
|
Модераторы: Partizan, gambit |
![]()
|
|
| Experimenter |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 430 Регистрация: 8.5.2007 Где: Уфа Репутация: 8 Всего: 17 |
Доброго здоровья, уважаемые!
Такой теоретический вопрос. Но сначала код:
Запускаем и видим, что потоки поочередно поднимаются и завершаются (по крайней мере, так консоль сообщает). Но по завершении всех потоков в Таск Менеджере напротив приложения вижу число потоков 29. Минуты через три убиваются, видимо сборщиком мусора. Вопрос такой: что не так и как этого избежать? Избежать именно в этом контексте (BeginInvoke и EndInvoke), System.Threading я уже освоил. -------------------- public Zlo FromTwoEvilsChooseSmaller(Zlo zlo1, Zlo zlo2){ if(zlo1 < zlo2) return zlo1; else if(zlo1 > zlo2) return zlo2; else throw new Exception("Kill yourself by the wall"); } |
|||
|
||||
| mr.DUDA |
|
|||
|
3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
Дело в том, что BeginInvoke работает черед ThreadPool, который выделяет потоки по необходимости. Если выделено одновременно 29 потоков, которые ждут N секунд и потом завершаются, ThreadPool справедливо предполагает что среднее кол-во потоков ещё некоторое время может оставаться на прежнем уровне, и держит их живыми. Потом убивает через какое-то время. Проверить эту гипотезу можно, вызвав в самом начале ThreadPool.SetMaxThreads(число, число).
-------------------- ![]() |
|||
|
||||
| Experimenter |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 430 Регистрация: 8.5.2007 Где: Уфа Репутация: 8 Всего: 17 |
mr.DUDA, да, кстати, это я уже проверял, так и работает, но я полагал, что потоки должны убиваться, когда они выполняют отведенный им код. Почему, когда я то же самое выполняю через System.Threading, никакие хвосты не остаются, если метод, выполняемый потоком, завершен? Дело в том, что я пишу приложения, которые работают круглосуточно, не хотелось бы допускать подобных нагрузок на систему.
-------------------- public Zlo FromTwoEvilsChooseSmaller(Zlo zlo1, Zlo zlo2){ if(zlo1 < zlo2) return zlo1; else if(zlo1 > zlo2) return zlo2; else throw new Exception("Kill yourself by the wall"); } |
|||
|
||||
| mr.DUDA |
|
|||
|
3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
Создание потока - действие, занимающее относительно большое время, поэтому в многопоточных приложениях в случае частого создания потоков они (потоки) используются повторно. На практике это означает, что функция потока запускается не пользователем а классом, назовём его пулом потоков, который ожидает вызова метода а-ля StartThread или QueueUserWorkItem, принимающего делегат (в С++ - указатель на функцию) на метод, выполняющий реальную задачу. Пул потоков проверяет, есть ли свободные потоки ("спящие" в данный момент) и если нет - создаёт новый поток. Если есть свободные - с помощью объектов синхронизации "пробуждает" поток (например, тот может ждать в WaitForSingleObject) и через общую переменную передаёт потоку указатель на функцию, которую необходимо выполнить. На этом роль пула потоков заканчивается, далее выбранный поток вызывает функцию и по выходу из неё "засыпает" до следующего раза. В таких случаях как веб-приложения ASP.NET, создание кучи потоков уступает использованию пула, т.к. реально потоков может потребоваться много и часто. Кроме того, пул потоков позволяет ставить запросы на создание потока в очередь в случае, если достигнут лимит одновременно выполняемых потоков. Ведь на самом деле, все потоки выполняются на одном, в лучшем случае - двух-четырёх процессорах, и одновременно выполняемые 50..100 потоков ощутимо нагрузят систему. -------------------- ![]() |
|||
|
||||
| 0000 |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 208 Регистрация: 11.7.2006 Где: Нижний Новгород Репутация: 2 Всего: 5 |
а почему при создании потока таким образом может вылазить NotSupportedException
и со в другом объекте вызываю этот Send... вылетает на нем эксепшн |
|||
|
||||
| Experimenter |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 430 Регистрация: 8.5.2007 Где: Уфа Репутация: 8 Всего: 17 |
0000, МСДН смотрел?
-------------------- public Zlo FromTwoEvilsChooseSmaller(Zlo zlo1, Zlo zlo2){ if(zlo1 < zlo2) return zlo1; else if(zlo1 > zlo2) return zlo2; else throw new Exception("Kill yourself by the wall"); } |
|||
|
||||
| 0000 |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 208 Регистрация: 11.7.2006 Где: Нижний Новгород Репутация: 2 Всего: 5 |
смотрел конечно...
тока не понимаю как к моему это привязано.. тут отсылаю файл, который в этот момент никак не читается, никак не обрабатывается я даже просто отдельно если создам объект A a = new A(); и вызываю a.Send() все равно выскакивает....а в новом объекте таким образом привязки к файлу вообще нет и в помине Это сообщение отредактировал(а) 0000 - 27.7.2007, 14:15 |
|||
|
||||
| Experimenter |
|
||||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 430 Регистрация: 8.5.2007 Где: Уфа Репутация: 8 Всего: 17 |
mr.DUDA, неубедительно. Вижу прямую противоположность в Таск Менеджере. При использовании System.Threading число потоков сначала возрастает по мере их загрузки, потом уменьшается по мере выполнения ими своих задач. Причем НЕМЕДЛЕННО! При асинхронных вызовах потоки висят в ТМ минуты три, не меньше. Если и там и тут используется ThreadPool, то почему он ведет себя по-разному? Значит еще какой-то фактор влияет!
Проверяется легко. Вместо кода:
ставим:
вместо:
ставим:
Запускаем консоли с разным кодом, запускаем Диспетчер задач и чувствуем разницу... P.S.: может в случае с асинхронными вызовами финализатор принудительно нужно вызывать каким-то образом? Надо будет попробовать... Добавлено через 7 минут и 35 секунд 0000, трудно вот так сказать сразу, я в МСДН в описании классов встречал такие приколы: мол, эта фича описана, но не поддерживается в текущей версии Фреймворка. Видимо на будущее заготовили... Это сообщение отредактировал(а) Experimenter - 27.7.2007, 17:54 -------------------- public Zlo FromTwoEvilsChooseSmaller(Zlo zlo1, Zlo zlo2){ if(zlo1 < zlo2) return zlo1; else if(zlo1 > zlo2) return zlo2; else throw new Exception("Kill yourself by the wall"); } |
||||||||
|
|||||||||
| stab |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 1839 Регистрация: 1.1.2003 Репутация: 22 Всего: 48 |
дуда как раз обратное говорит, что для асинхронных делегатов используется пул, а для прямой работы с Thread никаких пулов нет. -------------------- 6, 6, 6 - the number of the beast. |
|||
|
||||
| Experimenter |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 430 Регистрация: 8.5.2007 Где: Уфа Репутация: 8 Всего: 17 |
mr.DUDA, stab, то есть вы хотите сказать, что это нормальная ситуация, и нечего тут париться, да?
-------------------- public Zlo FromTwoEvilsChooseSmaller(Zlo zlo1, Zlo zlo2){ if(zlo1 < zlo2) return zlo1; else if(zlo1 > zlo2) return zlo2; else throw new Exception("Kill yourself by the wall"); } |
|||
|
||||
| stab |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 1839 Регистрация: 1.1.2003 Репутация: 22 Всего: 48 |
да, для асинхронных делегатов это абсолютно нормальная-рабочая ситуация.
-------------------- 6, 6, 6 - the number of the beast. |
|||
|
||||
| 0000 |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 208 Регистрация: 11.7.2006 Где: Нижний Новгород Репутация: 2 Всего: 5 |
то есть как я понимаю использование асинхронных вызовов от простого Thread.Start() отличается тем, что первые используют пул потоков???
а аналогично ли действует ThreadPool.QueueUserWorkItem(new WaitCallback(method), state);??? и преимущества его в чем?? в том, что ему не всегда необходимо создавать новый поток, а можно пробудить спящий??? |
|||
|
||||
| stab |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 1839 Регистрация: 1.1.2003 Репутация: 22 Всего: 48 |
0000, на все вопросы ответ да.
-------------------- 6, 6, 6 - the number of the beast. |
|||
|
||||
| 0000 |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 208 Регистрация: 11.7.2006 Где: Нижний Новгород Репутация: 2 Всего: 5 |
stab, коротко и ясно!! Спасибо =)
|
|||
|
||||
| Experimenter |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 430 Регистрация: 8.5.2007 Где: Уфа Репутация: 8 Всего: 17 |
Закрываем тему
-------------------- public Zlo FromTwoEvilsChooseSmaller(Zlo zlo1, Zlo zlo2){ if(zlo1 < zlo2) return zlo1; else if(zlo1 > zlo2) return zlo2; else throw new Exception("Kill yourself by the wall"); } |
|||
|
||||
![]()
|
| Прежде чем создать тему, посмотрите сюда: | |
|
|
Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов. Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :) Так же не забывайте отмечать свой вопрос решенным, если он таковым является :) Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |