So ermitteln Sie die Anzahl der CPUs mit Python

537

Ich möchte die Anzahl der CPUs auf dem lokalen Computer mit Python wissen. Das Ergebnis sollte user/realso ausgegeben werden, wie es time(1)aufgerufen wird, wenn es mit einem optimal skalierbaren Nur-Benutzer-Programm aufgerufen wird.

Phihag
quelle
3
Sie sollten cpusets (unter Linux) im Auge behalten. Wenn Sie sich in einem cpuset befinden, geben die folgenden Lösungen weiterhin die Anzahl der realen CPUs im System an, nicht die Anzahl, die Ihrem Prozess zur Verfügung steht. /proc/<PID>/statushat einige Zeilen, die Ihnen die Anzahl der CPUs im aktuellen cpuset mitteilen: suchen Sie nach Cpus_allowed_list.
wpoely86

Antworten:

854

Wenn Sie Python mit einer Version> = 2.6 haben, können Sie einfach verwenden

import multiprocessing

multiprocessing.cpu_count()

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

Nadia Alramli
quelle
4
Multiprocessing wird auch in 3.x
LittleByBlue
3
Ich möchte hinzufügen, dass dies in IronPython nicht funktioniert, wodurch ein NotImplementedError ausgelöst wird.
Matthias
1
Dies gibt die Anzahl der verfügbaren CPUs an ... die vom Programm nicht verwendet werden!
Amc
25
Auf Python 3.6.2 konnte ich nuros.cpu_count()
Achilles
4
Wie unten erwähnt, kann diese Anzahl auch "virtuelle" Hyperthread-CPUs umfassen, die möglicherweise nicht Ihren Wünschen entsprechen, wenn Sie CPU-intensive Aufgaben planen.
Christopher Barber
186

Wenn Sie an der Anzahl der Prozessoren interessiert sind, die für Ihren aktuellen Prozess verfügbar sind, müssen Sie zuerst cpuset überprüfen . Andernfalls (oder wenn cpuset nicht verwendet wird) multiprocessing.cpu_count()ist dies der richtige Weg in Python 2.6 und höher. Die folgende Methode greift auf einige alternative Methoden in älteren Versionen von Python zurück:

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
quelle
Auf einem MacPro 1.0 mit dem neuesten Ubuntu, auf einem HP Laptop mit einem aktuellen Debian und auf einer alten eMachine mit einem alten Ubuntu sind die cpus_allowed-Ergebnisse von /proc/self/statusff, f und f --- entsprechend 8, 4 und 4 nach Ihrer (richtigen) Mathematik. Die tatsächliche Anzahl der CPUs beträgt jedoch 4, 2 und 1. Ich finde, dass das Zählen der Anzahl der Vorkommen des Wortes "Prozessor" /proc/cpuinfoder bessere Weg sein kann. (Oder habe ich die Frage falsch?)
Mike O'Connor
1
Mit einigen weiteren Nachforschungen - wenn das von "Googeln" gesagt werden kann - finde ich aus der Verwendung /proc/cpuinfo, wenn Sie für eine der Auflistungen für jeden "Prozessor" die "Geschwister" mit den "CPU-Kernen" multiplizieren. Sie erhalten Ihre "Cpus_allowed" Nummer. Und ich stelle fest, dass sich die Geschwister auf Hyper-Threading beziehen, daher Ihr Hinweis auf "virtuell". Es bleibt jedoch die Tatsache, dass Ihre "Cpus_allowed" -Nummer auf meinem MacPro 8 ist, während Ihre multiprocessing.cpu_count()Antwort 4 ist. Meine eigene open('/proc/cpuinfo').read().count('processor')erzeugt auch 4, die Anzahl der physischen Kerne (zwei Dual-Core-Prozessoren).
Mike O'Connor
1
open('/proc/self/status').read()vergisst, die Datei zu schließen. Verwenden Sie with open('/proc/self/status') as f: f.read()stattdessen
timdiels
4
os.cpu_count()
Goetzc
1
@amcgregor In diesem Fall ist es akzeptabel, vereinbart, nur Dateihandles offen zu lassen, was meiner Meinung nach in Ordnung ist, wenn Sie keinen lang laufenden Daemon / Prozess schreiben. was ich befürchte, könnte am Ende eine maximale Anzahl offener Handles des Betriebssystems erreichen. Es ist schlimmer, wenn in eine Datei geschrieben wird, die vor dem Ende des Prozesses erneut gelesen werden muss, aber das ist hier nicht der Fall, daher ist dies ein strittiger Punkt. Es ist immer noch eine gute Idee, sich daran zu gewöhnen, withwenn Sie auf einen Fall stoßen, in dem Sie ihn brauchen.
Timdiels
91

Eine andere Möglichkeit ist die Verwendung der psutilBibliothek, die sich in folgenden Situationen immer als nützlich erweist:

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

Dies sollte auf jeder von psutil(Unix und Windows) unterstützten Plattform funktionieren .

Beachten Sie, dass in einigen Fällen multiprocessing.cpu_counteine NotImplementedErrorWeile psutildauern kann, um die Anzahl der CPUs zu ermitteln. Dies liegt einfach daran, dass psutilzuerst versucht wird, dieselben Techniken zu verwenden, die von verwendet werden, multiprocessingund wenn diese fehlschlagen, werden auch andere Techniken verwendet.

Bakuriu
quelle
4
Dieser ist wirklich gut, wenn man bedenkt, dass die verwendete Methode es ermöglicht herauszufinden, ob es sich bei den CPU-Kernen um logische oder physische Kerne handelt. psutil.cpu_count(logical = True)
Devilhunter
Hallo @ Bakuriu, gibt es eine Möglichkeit, die Anzahl der CPU-Kerne zu ermitteln, die von einem bestimmten Prozess mit psutil verwendet werden?
Saichand
@ Devilhunter Unter Windows auf meinem Intel i7-8700 psutil.cpu_count()gibt es 12 (es ist eine 6-Kern-CPU mit Hyperthreading). Dies liegt daran, dass das Standardargument von logicalTrue ist. Sie müssen also explizit schreiben psutil.cpu_count(logical = False), um die Anzahl der physischen Kerne zu ermitteln.
OscarVanL
52

In Python 3.4+: os.cpu_count () .

multiprocessing.cpu_count()wird in Bezug auf diese Funktion implementiert, wird jedoch ausgelöst, NotImplementedErrorwenn os.cpu_count()zurückgegeben wird None("Anzahl der CPUs kann nicht bestimmt werden").

jfs
quelle
4
Siehe auch die Dokumentation von cpu_count. len(os.sched_getaffinity(0))könnte je nach Zweck besser sein.
Albert
1
@ Albert ja, die Anzahl der CPUs im System (- os.cpu_count()was OP fragt) kann von der Anzahl der CPUs abweichen, die für den aktuellen Prozess verfügbar sind ( os.sched_getaffinity(0)).
JFS
Ich kenne. Ich wollte das nur für andere Leser hinzufügen, die diesen Unterschied vermissen könnten, um ein vollständigeres Bild von ihnen zu erhalten.
Albert
1
Außerdem: Das os.sched_getaffinity(0)ist auf BSD nicht verfügbar, daher ist die Verwendung von os.cpu_count()erforderlich (dh ohne andere externe Bibliothek).
Cometsong
1
Es sollte beachtet werden, dass os.sched_getaffinity unter Windows nicht verfügbar zu sein scheint.
Manu3d
47

len(os.sched_getaffinity(0)) ist das, was du normalerweise willst

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

os.sched_getaffinity(0)(in Python 3 hinzugefügt) gibt die verfügbaren CPUs unter Berücksichtigung des sched_setaffinityLinux-Systemaufrufs zurück , wodurch begrenzt wird, auf welchen CPUs ein Prozess und seine untergeordneten Komponenten ausgeführt werden können.

0bedeutet, den Wert für den aktuellen Prozess zu erhalten. Die Funktion gibt eine set()der zulässigen CPUs zurück, daher ist dies erforderlich len().

multiprocessing.cpu_count() Auf der anderen Seite wird nur die Gesamtzahl der physischen CPUs zurückgegeben.

Der Unterschied ist besonders wichtig, da bestimmte Cluster-Management-Systeme wie Platform LSF die CPU-Auslastung von Jobs einschränken sched_getaffinity.

Wenn Sie also verwenden multiprocessing.cpu_count(), versucht Ihr Skript möglicherweise, weit mehr Kerne als verfügbar zu verwenden, was zu Überlastung und Zeitüberschreitungen führen kann.

Wir können den Unterschied konkret erkennen, indem wir die Affinität zum tasksetNutzen einschränken .

Wenn ich beispielsweise Python in meinem 16-Kern-System auf nur 1 Kern (Kern 0) beschränke:

taskset -c 0 ./main.py

mit dem Testskript:

main.py.

#!/usr/bin/env python3

import multiprocessing
import os

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

dann ist die Ausgabe:

16
1

nproc respektiert jedoch standardmäßig die Affinität und:

taskset -c 0 nproc

Ausgänge:

1

und man nprocmacht das ganz deutlich:

Drucken Sie die Anzahl der verfügbaren Verarbeitungseinheiten

nprochat das --allFlag für den selteneren Fall, dass Sie die physische CPU-Anzahl erhalten möchten:

taskset -c 0 nproc --all

Der einzige Nachteil dieser Methode ist, dass dies anscheinend nur UNIX ist. Ich nahm an, dass Windows möglicherweise eine ähnliche Affinitäts-API haben muss SetProcessAffinityMask, also frage ich mich, warum es nicht portiert wurde. Aber ich weiß nichts über Windows.

Getestet in Ubuntu 16.04, Python 3.5.2.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
3
Nur unter Unix verfügbar.
Christopher Barber
@ChristopherBarber danke für die Info, die zur Antwort hinzugefügt wurde.
Ciro Santilli 7 冠状 病 六四 事件 7
33

Plattformunabhängig:

psutil.cpu_count (logisch = falsch)

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

Davoud Taghawi-Nejad
quelle
4
Was ist der Unterschied zwischen einer logischen und keiner logischen CPU? auf meinem Laptop: psutil.cpu_count(logical=False) #4 psutil.cpu_count(logical=True) #8undmultiprocessing.cpu_count() #8
user305883
1
@ user305883 Unter der Annahme, dass Sie eine x86-CPU haben, haben Sie Hyperthreading auf diesem Computer, dh jeder physische Kern entspricht zwei Hyperthreads ('logische' Kerne). Durch Hyperthreading kann der physische Kern verwendet werden, um Anweisungen von Thread B auszuführen, wenn Teile davon für Thread A inaktiv sind (z. B. darauf warten, dass Daten aus dem Cache oder Speicher abgerufen werden). Abhängig von Ihrem Code kann man ein oder einige zehn Prozent der zusätzlichen Kernauslastung erhalten, aber es liegt weit unter der Leistung eines echten physischen Kerns.
Andre Holzner
23

Diese geben Ihnen die Hyperthread-CPU-Anzahl

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

Diese geben Ihnen die CPU-Anzahl der virtuellen Maschine

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

Nur wichtig, wenn Sie auf VMs arbeiten.

yangliu2
quelle
Nicht wirklich. Wie bereits erwähnt, os.cpu_count()und multiprocessing.cpu_count()wird mit Hyper - Threading - CPU zählt zurückkehren, nicht die tatsächliche physische CPU - Anzahl.
Christopher Barber
2
Ja. Ich habe umformuliert. Es ist normalerweise die Anzahl der Kerne x 2. Ich meine, wenn Sie sich auf einer virtuellen Maschine befinden, die 8 Kerne herausgearbeitet hat, Ihre Host-Maschine jedoch physisch aus 20 Kernen besteht, erhalten Sie mit dem ersten Befehlssatz 20, mit dem zweiten Befehlssatz 20 8.
Yangliu2
21

multiprocessing.cpu_count()Gibt die Anzahl der logischen CPUs zurück. Wenn Sie also eine Quad-Core-CPU mit Hyperthreading haben, wird diese zurückgegeben 8. Wenn Sie die Anzahl der physischen CPUs angeben möchten, verwenden Sie die Python-Bindungen für hwloc:

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

hwloc ist für Betriebssysteme und Architekturen portierbar.

Douglas B. Staple
quelle
In diesem Fall möchte ich die Anzahl der logischen CPUs (dh wie viele Threads soll ich starten, wenn dieses Programm wirklich gut skaliert), aber die Antwort kann trotzdem hilfreich sein.
Phihag
7
oderpsutil.cpu_count(logical=False)
TimZaman
8

Ich kann nicht herausfinden, wie ich dem Code etwas hinzufügen oder auf die Nachricht antworten kann, aber hier ist die Unterstützung für Jython, die Sie einfügen können, bevor Sie aufgeben:

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

Dies mag für diejenigen von uns funktionieren, die verschiedene Betriebssysteme / Systeme verwenden, aber das Beste aus allen Welten herausholen möchten:

import os
workers = os.cpu_count()
if 'sched_getaffinity' in dir(os):
    workers = len(os.sched_getaffinity(0))
Konchog
quelle
5

Sie können zu diesem Zweck auch "joblib" verwenden.

import joblib
print joblib.cpu_count()

Diese Methode gibt Ihnen die Anzahl der CPUs im System. joblib muss allerdings installiert sein. Weitere Informationen zu joblib finden Sie hier https://pythonhosted.org/joblib/parallel.html

Alternativ können Sie das Python-Paket numexpr verwenden. Es hat viele einfache Funktionen, die hilfreich sind, um Informationen über die System-CPU zu erhalten.

import numexpr as ne
print ne.detect_number_of_cores()
amit12690
quelle
joblib verwendet das zugrunde liegende Multiprozessor-Modul. Es ist wahrscheinlich am besten, direkt in die Multiprozession zu wechseln.
Ogrisel
1

Eine weitere Option, wenn Sie nicht über Python 2.6 verfügen:

import commands
n = commands.getoutput("grep -c processor /proc/cpuinfo")
Alkero
quelle
2
Vielen Dank! Dies ist jedoch nur unter Linux verfügbar und bereits in meiner Antwort enthalten .
Phihag