Как узнать количество процессоров использующих python

537

Я хочу знать количество процессоров на локальной машине, использующих Python. Результат должен user/realвыводиться time(1)при вызове с помощью оптимально масштабируемой программы только для пространства пользователя.

phihag
источник
3
Вы должны помнить о процессорах (в Linux). Если вы работаете с процессором, приведенные ниже решения по-прежнему будут указывать количество реальных процессоров в системе, а не число, доступное для вашего процесса. /proc/<PID>/statusесть несколько строк, которые сообщают вам количество процессоров в текущем процессоре: ищите Cpus_allowed_list.
wpoely86

Ответы:

854

Если у вас есть Python с версией> = 2.6, вы можете просто использовать

import multiprocessing

multiprocessing.cpu_count()

http://docs.python.org/library/multiprocessing.html#multiprocessing.cpu_count

Надя Алрамли
источник
4
многопроцессорность также поддерживается в 3.x
LittleByBlue
3
Я хочу добавить, что это не работает в IronPython, который вызывает NotImplementedError.
Матиас
1
Это дает количество доступных процессоров ... не используемых программой!
17
25
На Python 3.6.2 я мог использовать толькоos.cpu_count()
Ахиллес
4
Кроме того, как отмечается ниже, в этот счетчик может входить «виртуальный» процессор с гиперпоточностью, который может быть не тем, что вам нужно, если вы планируете задачи с интенсивным использованием процессора.
Кристофер Барбер
186

Если вас интересует количество процессоров, доступных вашему текущему процессу, вам сначала нужно проверить cpuset . В противном случае (или если cpuset не используется), multiprocessing.cpu_count()это путь в Python 2.6 и новее. Следующий метод использует пару альтернативных методов в старых версиях Python:

import os
import re
import subprocess


def available_cpu_count():
    """ Number of available virtual or physical CPUs on this system, i.e.
    user/real as output by time(1) when called with an optimally scaling
    userspace-only program"""

    # cpuset
    # cpuset may restrict the number of *available* processors
    try:
        m = re.search(r'(?m)^Cpus_allowed:\s*(.*)$',
                      open('/proc/self/status').read())
        if m:
            res = bin(int(m.group(1).replace(',', ''), 16)).count('1')
            if res > 0:
                return res
    except IOError:
        pass

    # Python 2.6+
    try:
        import multiprocessing
        return multiprocessing.cpu_count()
    except (ImportError, NotImplementedError):
        pass

    # https://github.com/giampaolo/psutil
    try:
        import psutil
        return psutil.cpu_count()   # psutil.NUM_CPUS on old versions
    except (ImportError, AttributeError):
        pass

    # POSIX
    try:
        res = int(os.sysconf('SC_NPROCESSORS_ONLN'))

        if res > 0:
            return res
    except (AttributeError, ValueError):
        pass

    # Windows
    try:
        res = int(os.environ['NUMBER_OF_PROCESSORS'])

        if res > 0:
            return res
    except (KeyError, ValueError):
        pass

    # jython
    try:
        from java.lang import Runtime
        runtime = Runtime.getRuntime()
        res = runtime.availableProcessors()
        if res > 0:
            return res
    except ImportError:
        pass

    # BSD
    try:
        sysctl = subprocess.Popen(['sysctl', '-n', 'hw.ncpu'],
                                  stdout=subprocess.PIPE)
        scStdout = sysctl.communicate()[0]
        res = int(scStdout)

        if res > 0:
            return res
    except (OSError, ValueError):
        pass

    # Linux
    try:
        res = open('/proc/cpuinfo').read().count('processor\t:')

        if res > 0:
            return res
    except IOError:
        pass

    # Solaris
    try:
        pseudoDevices = os.listdir('/devices/pseudo/')
        res = 0
        for pd in pseudoDevices:
            if re.match(r'^cpuid@[0-9]+$', pd):
                res += 1

        if res > 0:
            return res
    except OSError:
        pass

    # Other UNIXes (heuristic)
    try:
        try:
            dmesg = open('/var/run/dmesg.boot').read()
        except IOError:
            dmesgProcess = subprocess.Popen(['dmesg'], stdout=subprocess.PIPE)
            dmesg = dmesgProcess.communicate()[0]

        res = 0
        while '\ncpu' + str(res) + ':' in dmesg:
            res += 1

        if res > 0:
            return res
    except OSError:
        pass

    raise Exception('Can not determine number of CPUs on this system')
phihag
источник
На MacPro 1,0 с последней версией Ubuntu, на ноутбуке HP с последней версией Debian и на старом eMachine с старой версией Ubuntu результаты cpus_allowed /proc/self/statusравны соответственно ff, f и f ---, что соответствует 8, 4 и 4 по вашей (правильной) математике. Однако фактическое количество процессоров составляет соответственно 4, 2 и 1. Я считаю, что подсчет числа появлений слова «процессор» /proc/cpuinfoможет быть лучшим способом. (Или у меня неправильный вопрос?)
Майк О'Коннор
1
С некоторыми дальнейшими исследованиями - если это можно сказать о "поиске в Google" - я обнаружил из использования, /proc/cpuinfoчто если для любого из списков для каждого "процессора" вы умножаете "братьев и сестер" на "ядра процессора" Вы получите свой номер "Cpus_allowed". И я понимаю, что братья и сестры относятся к гиперпоточности, отсюда ваша ссылка на «виртуальную». Но факт остается фактом: ваше число «Cpus_allowed» равно 8 на моем MacPro, а ваш multiprocessing.cpu_count()ответ - 4. Мой собственный open('/proc/cpuinfo').read().count('processor')также выдает 4, количество физических ядер (два двухъядерных процессора).
Майк О'Коннор
1
open('/proc/self/status').read()забывает закрыть файл. Используйте with open('/proc/self/status') as f: f.read()вместо этого
timdiels
4
os.cpu_count()
goetzc
1
@amcgregor В этом случае это приемлемо, согласен, просто оставить дескрипторы файлов открытыми, что, я думаю, нормально, если вы не пишете долго работающий демон / процесс; который, я боюсь, может в конечном итоге попасть в дескрипторы максимально открытого файла ОС. Хуже, когда вы записываете файл, который необходимо снова прочитать до завершения процесса, но здесь это не так, поэтому это спорный вопрос. Тем не менее, хорошая идея иметь привычку использовать, withкогда вы сталкиваетесь со случаем, когда вам это нужно.
Timdiels
91

Другой вариант - использовать psutilбиблиотеку, которая всегда оказывается полезной в следующих ситуациях:

>>> import psutil
>>> psutil.cpu_count()
2

Это должно работать на любой поддерживаемой платформе psutil(Unix и Windows).

Обратите внимание, что в некоторых случаях multiprocessing.cpu_countможет поднять некоторое NotImplementedErrorвремя psutilбудет возможность получить количество процессоров. Это просто потому, что psutilсначала пытается использовать те же методы, которые используются, multiprocessingи, если они терпят неудачу, он также использует другие методы.

Bakuriu
источник
4
Это действительно хорошо, учитывая, что используемый метод позволяет выяснить, являются ли ядра процессора логическими или физическими. psutil.cpu_count(logical = True)
Devilhunter
Привет @ Bakuriu, Есть ли способ получить количество ядер процессора, используемых конкретным процессом с использованием psutil?
Saichand
1
@Devilhunter В Windows на моем Intel i7-8700 psutil.cpu_count()выдает 12 (это 6-ядерный процессор с гиперпоточностью). Это связано с тем, что аргумент по умолчанию logical- True, поэтому вам явно нужно написать, psutil.cpu_count(logical = False)чтобы получить количество физических ядер.
OscarVanL
52

В Python 3.4+: os.cpu_count () .

multiprocessing.cpu_count()реализован в терминах этой функции, но повышается, NotImplementedErrorесли os.cpu_count()возвращает None(«не может определить количество процессоров»).

JFS
источник
4
Смотрите также документацию cpu_count. len(os.sched_getaffinity(0))может быть лучше, в зависимости от цели.
Альберт
1
@ Альберт, да, количество процессоров в системе ( os.cpu_count()что запрашивает OP) может отличаться от количества процессоров, доступных текущему процессу ( os.sched_getaffinity(0)).
JFS
Я знаю. Я просто хотел добавить это для других читателей, которые могут упустить эту разницу, чтобы получить от них более полную картину.
Альберт
1
А также: os.sched_getaffinity(0)это не доступно на BSD, поэтому использование os.cpu_count()не требуется (без других внешних библиотек, то есть).
Cometsong
1
Следует отметить, что os.sched_getaffinity, по-видимому, недоступен в Windows.
manu3d
47

len(os.sched_getaffinity(0)) это то, что вы обычно хотите

https://docs.python.org/3/library/os.html#os.sched_getaffinity

os.sched_getaffinity(0)(добавлено в Python 3) возвращает набор доступных процессоров с учетом sched_setaffinityсистемного вызова Linux , который ограничивает, на каких процессорах процесс и его дочерние элементы могут работать.

0означает получить значение для текущего процесса. Функция возвращает set()разрешенные ЦП, таким образом, необходимость len().

multiprocessing.cpu_count() с другой стороны, просто возвращает общее количество физических процессоров.

Разница особенно важна, потому что некоторые системы управления кластером, такие как Platform LSF, ограничивают использование ЦП заданием sched_getaffinity.

Поэтому, если вы используете multiprocessing.cpu_count(), ваш скрипт может попытаться использовать больше ядер, чем у него есть, что может привести к перегрузке и тайм-аутам.

Мы можем увидеть разницу конкретно, ограничив сродство с tasksetутилитой.

Например, если я ограничу Python только одним ядром (ядро 0) в моей 16-ядерной системе:

taskset -c 0 ./main.py

с тестовым скриптом:

main.py

#!/usr/bin/env python3

import multiprocessing
import os

print(multiprocessing.cpu_count())
print(len(os.sched_getaffinity(0)))

тогда вывод:

16
1

nproc однако по умолчанию соблюдает сходство и:

taskset -c 0 nproc

выходы:

1

и man nprocделает это довольно явным:

распечатать количество доступных единиц обработки

nprocимеет --allфлаг для менее распространенного случая, когда вы хотите получить физический счетчик ЦП:

taskset -c 0 nproc --all

Единственным недостатком этого метода является то, что это только UNIX. Я предположил, что Windows должен иметь похожий API-интерфейс, возможно SetProcessAffinityMask, поэтому я удивляюсь, почему он не был портирован. Но я ничего не знаю о Windows.

Протестировано в Ubuntu 16.04, Python 3.5.2.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
источник
3
Доступно только в Unix.
Кристофер Барбер
@ChristopherBarber спасибо за информацию, добавил к ответу.
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
34

Если вы хотите узнать количество физических ядер (не виртуальных гиперпоточных ядер), вот решение, не зависящее от платформы:

psutil.cpu_count(logical=False)

https://github.com/giampaolo/psutil/blob/master/INSTALL.rst

Обратите внимание, что значением по умолчанию logicalявляется True, поэтому, если вы хотите включить многопоточные ядра, вы можете использовать:

psutil.cpu_count()

Это даст тот же номер, что os.cpu_count()и multiprocessing.cpu_count(), и ни один из которых не имеет logicalключевое слово аргумент.

Давуд Тагави-Неджад
источник
4
В чем разница между логическим процессором и не логическим? на моем ноутбуке: psutil.cpu_count(logical=False) #4 psutil.cpu_count(logical=True) #8иmultiprocessing.cpu_count() #8
user305883
1
@ user305883 при условии, что у вас есть процессор x86, у вас есть гиперпоточность на этом компьютере, то есть каждое физическое ядро ​​соответствует двум гиперпотокам («логическим» ядрам). Гиперпоточность позволяет использовать физическое ядро ​​для выполнения инструкций из потока B, когда его части простаивают для потока A (например, ожидая получения данных из кэша или памяти). В зависимости от вашего кода можно получить один или несколько десятков процентов дополнительного использования ядра, но это намного ниже производительности реального физического ядра.
Андре Хольцнер
23

Они дают вам подсчитанное количество процессоров

  1. multiprocessing.cpu_count()
  2. os.cpu_count()

Они дают вам количество ЦП виртуальной машины

  1. psutil.cpu_count()
  2. numexpr.detect_number_of_cores()

Имеет значение только если вы работаете на виртуальных машинах.

yangliu2
источник
На самом деле, нет. Как уже отмечалось, os.cpu_count()и multiprocessing.cpu_count()будет возвращать количество многопоточных процессоров, а не фактическое количество физических процессоров.
Кристофер Барбер
2
Да. Я перефразировал. Обычно это число ядер x 2. Что я имею в виду, что если вы работаете на виртуальной машине, на которой установлено 8 ядер, но физически ваша хост-машина состоит из 20 ядер, то первый набор команд даст вам 20, второй набор команд даст вам 8.
yangliu2
21

multiprocessing.cpu_count()вернет количество логических процессоров, поэтому если у вас есть четырехъядерный процессор с гиперпоточностью, он вернется 8. Если вы хотите количество физических процессоров, используйте привязки python к hwloc:

#!/usr/bin/env python
import hwloc
topology = hwloc.Topology()
topology.load()
print topology.get_nbobjs_by_type(hwloc.OBJ_CORE)

hwloc предназначен для переноса между операционными системами и архитектурами.

Дуглас Б. Штапель
источник
В этом случае мне нужно количество логических процессоров (т. Е. Сколько потоков следует запустить, если эта программа действительно хорошо масштабируется), но, тем не менее, ответ может оказаться полезным.
phihag
7
илиpsutil.cpu_count(logical=False)
ТимЗаман
8

Не могу понять, как добавить код или ответить на сообщение, но вот поддержка jython, которую вы можете использовать перед тем, как сдаться:

# jython
try:
    from java.lang import Runtime
    runtime = Runtime.getRuntime()
    res = runtime.availableProcessors()
    if res > 0:
        return res
except ImportError:
    pass
Бен Шерри
источник
7

Это может работать для тех из нас, кто использует разные ОС / системы, но хочет получить лучшее из всех миров:

import os
workers = os.cpu_count()
if 'sched_getaffinity' in dir(os):
    workers = len(os.sched_getaffinity(0))
Кёнчог
источник
5

Вы также можете использовать "joblib" для этой цели.

import joblib
print joblib.cpu_count()

Этот метод даст вам количество процессоров в системе. joblib должен быть установлен, хотя. Более подробную информацию о joblib можно найти здесь https://pythonhosted.org/joblib/parallel.html

В качестве альтернативы вы можете использовать Numberxpr пакет Python. Он имеет много простых функций, полезных для получения информации о системном процессоре.

import numexpr as ne
print ne.detect_number_of_cores()
amit12690
источник
joblib использует базовый многопроцессорный модуль. Вероятно, для этого лучше всего обратиться к мультипроцессору.
Огризель
1

Другой вариант, если у вас нет Python 2.6:

import commands
n = commands.getoutput("grep -c processor /proc/cpuinfo")
Alkero
источник
2
Спасибо! Это доступно только в Linux, и уже включено в мой ответ .
phihag