Информирование ThreadPool.QueueUserWorkItem о требованиях к памяти

Мы разрабатываем приложение, в котором пользователи могут запускать несколько задач одновременно. Мы используем ThreadPool.QueueUserWorkItem для запуска задач. Эта часть работает хорошо.

У нас есть проблема, когда эти задачи могут потреблять более 500 МБ памяти. Мы используем ввод-вывод с отображением памяти для управления памятью. Тем не менее, когда пользователи устанавливают более 10 задач, работающих одновременно, пул потоков запускает их все, и были случаи, когда у нас заканчивалась память и возникали исключения. Мы прекрасно справляемся с ошибками.

Мне интересно, есть ли способ учесть память, которая будет потребляться при обработке очереди, то есть держать задачи в очереди до тех пор, пока не будет достаточно памяти? Могу ли я сообщить пулу потоков о том, сколько памяти мы будем запрашивать (что мы можем приблизительно оценить)?


person Walter Williams    schedule 27.01.2012    source источник
comment
Не похоже на правильное использование пула потоков. Потоки TP должны выполнять только короткие короткие порции работы, не более чем за полсекунды. Используйте ограниченное количество объектов Thread, не более Environment.ProcessorCount, и поточно-ориентированную очередь, чтобы дать им работу.   -  person Hans Passant    schedule 27.01.2012
comment
Спасибо, думаю что с таким подходом напишем свой пул.   -  person Walter Williams    schedule 30.01.2012


Ответы (3)


ThreadPool ничего не знает о том, что вы делаете в своих задачах. Вы должны убедиться в этом сами. Вы можете управлять глобальной переменной типа long, представляющей общее количество байтов, которое, вероятно, потребуется всем работающим заданиям на пике нагрузки. Когда пул потоков планирует одну из ваших задач, вы сначала проверяете эту переменную. Если он уже слишком высок, подождите, пока не завершится любая работающая в данный момент задача. Затем вы снова проверяете.

Низкотехнологичное решение этой проблемы — использовать опрос с интервалом ожидания 100 мс. В высокотехнологичной версии использовалась бы какая-то схема ожидания, включающая события.

person usr    schedule 27.01.2012

Хорошо, если вы можете получить оценку памяти для каждой задачи, вы, вероятно, могли бы сделать это, сохраняя в пуле приблизительный подсчет использования памяти, защищенный CS. Добавьте к этому счету непосредственно перед отправкой задачи, и пусть задача вызовет функцию memRelease, чтобы вычесть из нее непосредственно перед ее завершением и проверить, можно ли что-либо запустить сейчас (см. Ниже).

Если какой-то поток хочет отправить задачу и обнаруживается (путем сравнения его потребностей с текущим использованием внутри CS), что в «бюджете» недостаточно памяти для его запуска, вы можете засунуть его в параллельную очередь. /list ждать, пока не будет. Всякий раз, когда задача завершается и вызывает «memRelease», она добавляется к багету памяти и перебирает очередь/список (сначала блокируя его), чтобы попытаться найти что-то, что теперь можно запустить с увеличенной доступной памятью. Если это так, он отправляет задачу в пул.

person Martin James    schedule 27.01.2012
comment
Возможно, есть некоторые проблемы - сильно загруженная система может заблокировать задачу с высокими требованиями к памяти, постоянно загружая вновь поступившие задачи с меньшими требованиями. Возможно применение какого-то алгоритма защиты от голодания, возможно, путем повторения списка «ожидающих» при добавлении задач, чтобы решить, отправлять ли новую задачу или просто добавить ее в конец списка ожидающих выполнения, чтобы создать достаточно памяти для запустить какую-то отложенную задачу, которая требует многого и давно ждет. - person Martin James; 27.01.2012

Вы можете контролировать количество потоков в пуле потоков с помощью ThreadPool.SetMaxThreads. Итак, что вы можете сделать, это установить максимальное количество потоков

ThreadPool.SetMaxThreads = new PerformanceCounter("Memory", "Available MBytes").RawValue / 500;

PerformanceCounter("Память", "Доступные МБ").RawValue -> Возвращает доступную память в МБ

person Vlad Bezden    schedule 27.01.2012
comment
Это глобальная настройка процесса. Вы определенно не должны этого делать. Не решайте локальную проблему с помощью локального решения. Также это не решает проблему, потому что у заданий разные требования к памяти. Статическое максимальное количество потоков не может быть найдено. - person usr; 27.01.2012