Многопроцессорность не позволяет полностью использовать процессор на двухпроцессорной машине с Windows
Я работаю на двухпроцессорной машине с Windows и пытаюсь запустить несколько независимых процессов Python, используя многопроцессорную библиотеку. Конечно, я стремлюсь максимально использовать оба процессора, чтобы ускорить время вычислений. Детали моей машины ниже:
- ОС: Windows 10 Pro для рабочих станций
- Оперативная память: 524 ГБ
- Жесткий диск: Samsung SSD PRO 960 (NVMe)
- Процессор: Xeon Gold 6154 (раз 2)
Я выполняю мастер-скрипт с использованием Python 3.6, который затем порождает 72 независимых от памяти рабочих, использующих многопроцессорную библиотеку. Изначально все 72 ядра моей машины используются на все 100%. Однако примерно через 5-10 минут все 36 ядер моего второго ЦП сокращают использование до 0%, а 36 ядер первого ЦП остаются на уровне 100%. Я не могу понять, почему это происходит.
Есть ли что-то, чего мне не хватает в отношении использования обоих процессоров на двухпроцессорной машине с Windows? Как я могу гарантировать, что весь потенциал моей машины используется? Как примечание, мне интересно, если бы я использовал ОС Linux, было бы по-другому? Заранее благодарю всех, кто готов помочь с этим.
Представление моего основного сценария Python ниже:
import pandas as pd
import netCDF4 as nc
from multiprocessing import Pool
WEATHERDATAPATH = "C:/Users/..../weatherdata/weatherfile_%s.nc4"
OUTPUTPATH = "C:/Users/....outputs/result_%s.nc4"
def calculationFunction(year):
dataset = nc.Dataset(WEATHERDATAPATH%year)
# Read the data
data1 = dataset["windspeed"][:]
data2 = dataset["pressure"][:]
data3 = dataset["temperature"][:]
timeindex = nc.num2date(dataset["time"][:], dataset["time"].units)
# Do computations with the data, primarily relying on NumPy
data1Mean = data1.mean(axis=1)
data2Mean = data2.mean(axis=1)
data3Mean = data3.mean(axis=1)
# Write result to a file
result = pd.DataFrame( {"windspeed":data1Mean,
"pressure":data2Mean,
"temperature":data3Mean,},
index=timeindex )
result.to_csv(OUTPUTPATH%year)
if __name__ == '__main__':
pool = Pool(72)
results = []
for year in range(1900,2016):
results.append( pool.apply_async(calculationFunction, (year, )))
for r in results: r.get()
2 ответа
Оказывается, проблема была с NumPy. Как объясняет это решение, NumPy и несколько других аналогичных пакетов полагаются на библиотеку BLAS для выполнения числовых операций. Эта библиотека использует многопоточность для увеличения производительности. Но поскольку многопоточность привязана к процессору, это заставляет многие операции, выполняемые Numpy (которые в моем исходном коде не начинаются до середины, как я уже указывал), принудительно переноситься на первый процессор.
Решение состоит в том, чтобы отключить многопоточность библиотеки BLAS. Я не уверен, влияет ли это на производительность, но в этом случае я думаю, что все будет хорошо. К счастью, это легко сделать, мне нужно было установить только одну переменную окружения, которую я сделал прямо в своем коде Python:
import os
os.environ["OPENBLAS_MAIN_FREE"] = "1"
Теперь машина работает на полную мощность по всему моему коду:)
Это может быть связано с парковкой ядра Windows .
Удивительно, но в сети нет четкого описания этой функции, только клочки информации.
По сути, чем больше задействовано ядер / процессоров, тем выше накладные расходы на синхронизацию (квадратично) и энергопотребление. Таким образом, Win7+ пытается использовать наименьшее количество ядер / процессоров, достаточных для текущей рабочей нагрузки. Аналогично, синхронизация SMP имеет другие издержки по сравнению с межъядерной синхронизацией - вероятно, выше, потому что ЦПУ требуется заблокировать шину совместно используемой памяти для выполнения операций блокировки, полностью отключая другие ЦП, в то время как ядра имеют больший запас времени, поскольку нет никаких отраслевых стандартов, регулирующих то, что происходит внутри процессора.
Ваши задачи частично связаны с процессором, частично связаны с вводом / выводом. В ПК массовый ввод-вывод обычно выполняется с помощью DMA, что позволяет центральному процессору переключаться на другие функции. Таким образом, теоретически ваша рабочая нагрузка может обрабатываться меньшим количеством ядер, чем рабочими.
Во-первых, вам нужно проверить, так ли это. В конце концов, может быть, просто некоторые работники завершили, а некоторые еще нет.
Прежде всего, вы можете запустить диспетчер задач после загрузки и посмотреть, помечено ли какое-либо из ядер "Запарковано".
Затем используйте эти распечатки отладки в рабочей функции между шагами, чтобы выяснить, где она в данный момент выполняется:
print("PID: %d, CPU: %d"%(os.getpid(),ctypes.windll.kernel32.GetCurrentProcessorNumber())
- Поток может быть запланирован на другой процессор каждый раз, когда он получает контроль (время слота составляет ~10 мс в Windows IIRC). Таким образом, отдельные числа ничего не значат, только статистические данные. Win7+ пытается запланировать один и тот же поток на одно и то же ядро, когда это практически возможно, чтобы уменьшить необходимость в очистке кеша.
Кроме того, вы можете редактировать trace.py:localtrace_trace()
в стандартной библиотеке, чтобы отобразить эту информацию и запустить вашу программу с трассировкой, чтобы получить больше статистики (обратите внимание, что огромное количество трассировки изменит рабочую нагрузку в направлении ввода-вывода, поэтому будьте осторожны при интерпретации результатов).
Теперь, если это окажется основной парковкой, вот как вы ее контролируете.
MS не публикует эту информацию - вероятно, потому что они хотят свободы, чтобы изменить это, или потому что это слишком глубоко для подавляющего большинства пользователей, чтобы использовать осмысленно.
- Идти к
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\PowerSettings\54533251-82be-4824-96c1-47b60b740d00\
, В значениях вы увидите, что это реестр параметров питания процессора в приложении "Панель управления параметрами питания". - Многие из них имеют
Attributes
ценность00000001
(набор наименее значимых битов), что означает, что они скрыты от графического интерфейса приложения. Чтобы их показать, нужно- сбросьте LSB в значении реестра, или
- запустите `powercfg -attributes -ATTRIB_HIDE, который будет делать то же самое
Так как MS не объясняет, какое значение делает то, что (все, что у нас есть, это текст объяснения в этих разделах реестра - который также отображается в графическом интерфейсе, если вы скрываете настройки), существует большая путаница относительно их значения в сети - в том числе и из утилитарных писателей.
По крайней мере, настройка "Processor performance core parking min cores"
до 100% будет эффективно отключать парковку (но не в режиме ожидания и управления частотой).
Мощность и производительность Тюнинг | В Microsoft Docs говорится, что для серверных систем Windows профиль "High Performace" полностью отключает парковку и регулирование частоты, поэтому наиболее надежным способом является получение одной из этих ОС и копирование всех настроек из этого профиля.