Як дізнатися кількість процесорів за допомогою python


537

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


3
Ви повинні пам’ятати про cpusets (в 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
Це дає кількість доступних процесорів ... не використовується програмою!
amc

25
На Python 3.6.2 я міг користуватися лишеos.cpu_count()
Ахілл

4
Крім того, як зазначено нижче, до цього рахунку може входити "віртуальний" гіпертоковий процесор, який може бути не тим, що ви хочете, якщо плануєте завдання, що займають процесорне забезпечення.
Крістофер Барбер

185

Якщо вас цікавить кількість процесорів, доступних для вашого поточного процесу, вам слід спочатку перевірити 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')

На 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
З деякими подальшими дослідженнями --- якщо це можна сказати про "Гуглінг" --- я знаходжу з використання цього /proc/cpuinfo, якщо для будь-якого з списків кожного "процесора" ви помножите "братів і сестер" на "ядра процесора" ви отримуєте свій номер "Cpus_allowed". І я вважаю, що побратими відносяться до гіперточок, звідси ваше посилання на "віртуальне". Але факт залишається фактом, що у вашому MacPro число "Cpus_allowed" - 8, тоді як ваша 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коли ви стикаєтеся з випадком, коли це вам потрібно.
тайм’єли

91

Іншим варіантом є використання psutilбібліотеки, яка завжди виявляється корисною в таких ситуаціях:

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

Це має працювати на будь-якій платформі, підтримуваній psutil (Unix та Windows).

Зауважте, що в деяких випадках multiprocessing.cpu_countможе збільшитись NotImplementedErrorчас psutil, зможете отримати кількість процесорів. Це просто тому, що psutilспочатку намагаються використовувати ті самі методи, якими вони користуються, multiprocessingа якщо вони не вдаються, вони також використовують інші методи.


4
Це дійсно добре, враховуючи, що використовуваний метод дозволяє з'ясувати, чи є ядра CPU - це логічно руди фізичні. psutil.cpu_count(logical = True)
Devilhunter

Привіт @ Бакуріу, чи є спосіб отримати кількість ядер процесора, використовуваних у конкретному процесі за допомогою psutil?
saichand

@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("не вдається визначити кількість процесорів").


4
Дивіться також документацію про cpu_count. len(os.sched_getaffinity(0))може бути краще, залежно від мети.
Альберт

1
@Albert так, кількість ЦП в системі (— os.cpu_count()що запитує ОП) може відрізнятися від кількості ЦП, доступних для поточного процесу ( 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() з іншого боку, просто повертає загальну кількість фізичних процесорів.

Різниця особливо важлива, оскільки деякі системи управління кластерами, такі як платформа LSF, обмежують використання CPU у роботіsched_getaffinity .

Тому, якщо ви використовуєте multiprocessing.cpu_count() , ваш скрипт може спробувати використати набагато більше ядер, ніж є в наявності, що може призвести до перевантаження та затримки часу.

Ми можемо бачити різницю конкретно, обмежуючи спорідненість із taskset утилітою.

Наприклад, якщо я обмежую Python лише 1 ядром (core 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.


3
Доступно лише в Unix.
Крістофер Барбер

@ChristopherBarber дякую за інформацію, додану до відповіді.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

33

платформа незалежна:

psutil.cpu_count (логічно = помилково)

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


4
Чим відрізняється логічний процесор від не логічного? на моєму ноутбуці: psutil.cpu_count(logical=False) #4 psutil.cpu_count(logical=True) #8таmultiprocessing.cpu_count() #8
user305883

1
@ User305883 якщо у вас є на x86 CPU, ви повинні гіперпоточность на цій машині, тобто кожна фізична ядро відповідає двом hyperthreads ( «логічні» ядра). Hyperthreading дозволяє використовувати фізичне ядро ​​для виконання інструкцій з потоку B, коли його частини в режимі очікування для потоку A (наприклад, очікування отримання даних з кешу чи пам'яті). Залежно від вашого коду, ви можете отримати одну чи кілька десятків відсотків додаткового використання ядра, але це значно нижче продуктивності фізичного ядра.
Андре Хольцнер

23

Вони дають вам підрахунок процесора

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

Вони дають вам кількість процесорів віртуальної машини

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

Має значення лише те, якщо ви працюєте на віртуальних машинах.


Не зовсім. Як зазначалося, 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 розроблений так, щоб він був портативним в ОС та архітектурах.


У цьому випадку я хочу кількість логічних процесорів (тобто, скільки ниток потрібно запустити, якщо ця програма масштабує дуже добре), але відповідь, тим не менш, може бути корисною.
фігаг

7
абоpsutil.cpu_count(logical=False)
TimZaman

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()

Цей метод дасть вам кількість cpus в системі. joblib потрібно встановити. Більше інформації про joblib можна знайти тут https://pythonhosted.org/joblib/parallel.html

Крім того, ви можете використовувати numexpr пакет python. У ньому багато простих функцій, корисних для отримання інформації про системний процесор.

import numexpr as ne
print ne.detect_number_of_cores()

joblib використовує базовий багатопроцесорний модуль. Для цього, мабуть, найкраще закликатись до багатопроцесорної обробки.
ogrisel

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.