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

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

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

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

3 ответа

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

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

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

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

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

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

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

Другие вопросы по тегам