Вопрос:
Я использую multiprocessing.Pool.imap для запуска нескольких независимых заданий параллельно с использованием Python 2.7 в Windows 7. С настройками по умолчанию мое общее использование ЦП привязано к 100%, как измерено диспетчером задач Windows. Это делает невозможным выполнение какой-либо другой работы, пока мой код работает в фоновом режиме.
Я попытался ограничить количество процессов числом процессоров минус 1, как описано в разделе Как ограничить количество процессоров, которые использует Python:
pool = Pool(processes=max(multiprocessing.cpu_count()-1, 1) for p in pool.imap(func, iterable): …
Это уменьшает общее количество запущенных процессов. Тем не менее, каждый процесс просто занимает больше циклов, чтобы компенсировать это. Таким образом, мое общее использование ЦП по-прежнему привязано к 100%.
Есть ли способ напрямую ограничить общее использование ЦП – НЕ только количество процессов – или если это не так, есть ли какое-либо обходное решение?
Лучший ответ:
Решение зависит от того, что вы хотите сделать. Вот несколько вариантов:
Содержание
Нижние приоритеты процессов
Вы можете nice подпроцессы. Таким образом, хотя они будут по-прежнему потреблять 100% процессора, когда вы запускаете другие приложения, ОС отдает предпочтение другим приложениям. Если вы хотите оставить интенсивный расчет на psutils на заднем плане вашего ноутбука и не заботитесь о том, что вентилятор процессора работает все время, то хорошим psutils является ваше решение. Этот скрипт является тестовым скриптом, который работает на всех ядрах в течение достаточного времени, чтобы вы могли видеть, как он себя ведет.
from multiprocessing import Pool, cpu_count import math import psutil import os def f(i): return math.sqrt(i) def limit_cpu(): «is called at every process start» p = psutil.Process(os.getpid()) # set to lowest priority, this is windows only, on Unix use ps.nice(19) p.nice(psutil.BELOW_NORMAL_PRIORITY_CLASS) if __name__ == ‘__main__’: # start «number of cores» processes pool = Pool(None, limit_cpu) for p in pool.imap(f, range(10**8)): pass
Фокус в том, что limit_cpu запускается в начале каждого процесса (см. Раздел initializer в документе). В то время как Unix имеет уровни -19 (самый высокий приоритет) до 19 (самый низкий prio), Windows имеет несколько отдельных уровней для отдачи приоритета. BELOW_NORMAL_PRIORITY_CLASS вероятно, лучше всего соответствует вашим требованиям, также существует IDLE_PRIORITY_CLASS котором говорится, что Windows запускает ваш процесс только в том случае, если система не работает.
Вы можете просмотреть приоритет, если переключитесь в режим подробностей в диспетчере задач и щелкните правой кнопкой мыши процесс:
Меньшее число процессов
Хотя вы отклонили эту опцию, все же может быть хорошим вариантом: скажем, вы ограничиваете количество подпроцессов половиной ядер процессора с помощью pool = Pool(max(cpu_count()//2, 1)) тогда ОС изначально запускает эти процессы на половине ядер процессора, в то время как остальные остаются бездействующими или просто запускают другие приложения, которые в настоящее время работают. Через короткое время ОС перестроит процессы и может переместить их в другие ядра процессора и т.д. Оба Windows, как системы на основе Unix, ведут себя таким образом.
Windows: запуск 2 процессов на 4 ядрах:
OSX: запуск 4 процессов на 8 ядрах:
Вы видите, что обе ОС балансируют процесс между ядрами, хотя и неравномерно, поэтому вы по-прежнему видите несколько ядер с более высоким процентом, чем другие.
Спать
Если вы абсолютно уверены, что ваши процессы никогда не будут потреблять 100% определенного ядра (например, если вы хотите, чтобы вентилятор процессора увеличивался), вы можете запустить сон в своей функции обработки:
from time import sleep def f(i): sleep(0.01) return math.sqrt(i)
Это заставляет ОС “расписывать” ваш процесс в течение 0.01 секунды для каждого вычисления и освобождает место для других приложений. Если других приложений нет, то ядро процессора остается бездействующим, поэтому оно никогда не перейдет на 100%. Вам нужно будет поиграть с разной продолжительностью сна, это также будет варьироваться от компьютера к компьютеру, на котором вы его запускаете. Если вы хотите сделать это очень сложным, вы можете адаптировать сон в зависимости от того, что cpu_times().