Многопроцессорность не позволяет полностью использовать процессор на двухпроцессорной машине с 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" полностью отключает парковку и регулирование частоты, поэтому наиболее надежным способом является получение одной из этих ОС и копирование всех настроек из этого профиля.

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