Comment connaître le nombre de processeurs utilisant python


537

Je veux connaître le nombre de processeurs sur la machine locale utilisant Python. Le résultat doit être user/realproduit en sortie par un time(1)appel avec un programme uniquement à espace utilisateur à échelle optimale.


3
Vous devez garder à l'esprit les cpusets (sous Linux). Si vous êtes dans un cpuset, les solutions ci-dessous donneront toujours le nombre de CPU réels dans le système, pas le nombre disponible pour votre processus. /proc/<PID>/statusa quelques lignes qui vous indiquent le nombre de processeurs dans le cpuset actuel: recherchez Cpus_allowed_list.
wpoely86

Réponses:


854

Si vous avez python avec une version> = 2.6, vous pouvez simplement utiliser

import multiprocessing

multiprocessing.cpu_count()

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


4
multiprocessing est également pris en charge dans 3.x
LittleByBlue

3
Je veux ajouter que cela ne fonctionne pas dans IronPython, ce qui déclenche une erreur NotImplementedError.
Matthias

1
Cela donne le nombre de CPU disponibles ... non utilisés par le programme!
amc

25
Sur Python 3.6.2, je ne pouvais utiliser queos.cpu_count()
Achilles

4
En outre, comme indiqué ci-dessous, ce nombre peut inclure des processeurs virtuels hyperthreadés, qui peuvent ne pas être ce que vous voulez si vous planifiez des tâches gourmandes en processeurs.
Christopher Barber

186

Si vous êtes intéressé par le nombre de processeurs disponibles pour votre processus actuel, vous devez d'abord vérifier cpuset . Sinon (ou si cpuset n'est pas utilisé), multiprocessing.cpu_count()c'est la voie à suivre en Python 2.6 et plus récent. La méthode suivante revient à quelques méthodes alternatives dans les anciennes versions de 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')

Sur un MacPro 1.0 exécutant la dernière Ubuntu, sur un ordinateur portable HP exécutant une Debian récente et sur un ancien eMachine exécutant une ancienne Ubuntu, les résultats cpus_allowed de /proc/self/statussont respectivement ff, f et f --- correspondant à 8, 4 et 4 par votre (correct) calcul. Cependant, le nombre réel de CPU est respectivement de 4, 2 et 1. Je trouve que compter le nombre d'occurrences du mot "processeur" /proc/cpuinfopeut être la meilleure façon de procéder. (Ou ai-je une mauvaise question?)
Mike O'Connor

1
Avec quelques recherches supplémentaires --- si cela peut être dit de "Google" --- je trouve de l'utilisation de /proc/cpuinfocela si pour l'une des listes de chaque "processeur" vous multipliez les "frères et sœurs" par les "cœurs de processeur" vous obtenez votre numéro "Cpus_allowed". Et je suppose que les frères et sœurs se réfèrent à l'hyper-threading, d'où votre référence au "virtuel". Mais le fait demeure que votre numéro "Cpus_allowed" est 8 sur mon MacPro alors que votre multiprocessing.cpu_count()réponse est 4. Le mien open('/proc/cpuinfo').read().count('processor')produit également 4, le nombre de cœurs physiques (deux processeurs dual-core).
Mike O'Connor

1
open('/proc/self/status').read()oublie de fermer le fichier. Utilisez with open('/proc/self/status') as f: f.read()plutôt
timdiels

4
os.cpu_count()
goetzc

1
@amcgregor Dans ce cas, c'est acceptable, d'accord, seuls les descripteurs de fichiers sont laissés ouverts, ce qui, je suppose, est correct si vous n'écrivez pas un démon / processus de longue durée; qui, je le crains, pourrait finir par atteindre un maximum de descripteurs de fichiers ouverts du système d'exploitation. C'est pire lorsque vous écrivez dans un fichier qui doit être relu avant la fin du processus, mais ce n'est pas le cas ici, c'est donc un point discutable. C'est toujours une bonne idée d'avoir l'habitude de l'utiliser withlorsque vous rencontrez un cas où vous en avez besoin.
timdiels

91

Une autre option consiste à utiliser la psutilbibliothèque, qui s'avère toujours utile dans ces situations:

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

Cela devrait fonctionner sur n'importe quelle plate-forme prise en charge par psutil(Unix et Windows).

Notez que, dans certaines occasions, multiprocessing.cpu_countpeut soulever un NotImplementedErrorcertain temps psutilsera en mesure d'obtenir le nombre de processeurs. C'est tout simplement parce que psutiltente d'abord d'utiliser les mêmes techniques utilisées par multiprocessinget, si celles-ci échouent, il utilise également d'autres techniques.


4
Celui-ci est vraiment bon, étant donné que la méthode utilisée permet de savoir si les cœurs de processeur sont des cœurs physiques ou logiques. psutil.cpu_count(logical = True)
Devilhunter

Salut @Bakuriu, Existe-t-il un moyen d'obtenir le nombre de cœurs de processeur utilisés par un processus spécifique à l'aide de psutil?
saichand

1
@Devilhunter Sous Windows sur mon Intel i7-8700 psutil.cpu_count()donne 12 (c'est un processeur 6 cœurs avec hyperthreading). En effet, l'argument par défaut de logicalest True, vous devez donc explicitement écrire psutil.cpu_count(logical = False)pour obtenir le nombre de cœurs physiques.
OscarVanL

52

En Python 3.4+: os.cpu_count () .

multiprocessing.cpu_count()est implémenté en termes de cette fonction mais augmente NotImplementedErrorsi os.cpu_count()renvoie None("ne peut pas déterminer le nombre de CPU").


4
Voir aussi la documentation de cpu_count. len(os.sched_getaffinity(0))pourrait être mieux, selon le but.
Albert

1
@Albert oui, le nombre de CPU dans le système ( os.cpu_count()ce que demande OP) peut différer du nombre de CPU disponibles pour le processus en cours ( os.sched_getaffinity(0)).
jfs

Je connais. Je voulais juste ajouter cela pour d'autres lecteurs, qui pourraient manquer cette différence, pour obtenir une image plus complète d'eux.
Albert

1
Aussi: le os.sched_getaffinity(0)n'est pas disponible sur BSD, donc l'utilisation de os.cpu_count()est requise (sans autre bibliothèque externe, c'est-à-dire).
Cometsong

1
Il convient de noter que os.sched_getaffinity ne semble pas être disponible sous Windows.
manu3d

47

len(os.sched_getaffinity(0)) c'est ce que tu veux d'habitude

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

os.sched_getaffinity(0)(ajouté dans Python 3) renvoie l'ensemble des processeurs disponibles compte tenu de l' sched_setaffinityappel système Linux , ce qui limite les processeurs sur lesquels un processus et ses enfants peuvent s'exécuter.

0signifie obtenir la valeur du processus en cours. La fonction renvoie un set()des CPU autorisés, d'où la nécessité len().

multiprocessing.cpu_count() d'autre part, renvoie simplement le nombre total de CPU physiques.

La différence est particulièrement importante car certains systèmes de gestion de cluster tels que Platform LSF limitent l'utilisation du processeur de travail avec sched_getaffinity.

Par conséquent, si vous utilisez multiprocessing.cpu_count(), votre script peut essayer d'utiliser beaucoup plus de cœurs qu'il n'en a, ce qui peut entraîner une surcharge et des délais d'attente.

On peut voir la différence concrètement en restreignant l'affinité avec l' tasksetutilité.

Par exemple, si je limite Python à seulement 1 cœur (cœur 0) dans mon système à 16 cœurs:

taskset -c 0 ./main.py

avec le script de test:

main.py

#!/usr/bin/env python3

import multiprocessing
import os

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

alors la sortie est:

16
1

nproc respecte cependant l'affinité par défaut et:

taskset -c 0 nproc

les sorties:

1

et man nprocrend cela assez explicite:

imprimer le nombre d'unités de traitement disponibles

nproca l' --allindicateur pour le cas le moins courant où vous souhaitez obtenir le nombre d'UC physiques:

taskset -c 0 nproc --all

Le seul inconvénient de cette méthode est qu'elle semble être uniquement UNIX. Je supposais que Windows devait avoir une API d'affinité similaire SetProcessAffinityMask, donc je me demande pourquoi il n'a pas été porté. Mais je ne connais rien de Windows.

Testé dans Ubuntu 16.04, Python 3.5.2.


3
Uniquement disponible sur Unix.
Christopher Barber

@ChristopherBarber merci pour l'info, ajoutée à la réponse.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

34

Si vous souhaitez connaître le nombre de cœurs physiques (pas les cœurs virtuels hyperthreadés), voici une solution indépendante de la plateforme:

psutil.cpu_count(logical=False)

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

Notez que la valeur par défaut de logicalest True, donc si vous souhaitez inclure des cœurs hyperthreadés, vous pouvez utiliser:

psutil.cpu_count()

Cela donnera le même nombre que os.cpu_count()et multiprocessing.cpu_count(), dont aucun n'a l' logicalargument mot - clé.


4
Quelle est la différence entre un processeur logique et non pas logique? sur mon ordinateur portable: psutil.cpu_count(logical=False) #4 psutil.cpu_count(logical=True) #8etmultiprocessing.cpu_count() #8
user305883

1
@ user305883 en supposant que vous avez un CPU x86, vous avez de l' hyperthreading sur cette machine, c'est-à-dire que chaque cœur physique correspond à deux hyperthreads (cœurs «logiques»). L'hyperthreading permet au noyau physique d'être utilisé pour exécuter des instructions à partir du thread B lorsque des parties de celui-ci sont inactives pour le thread A (par exemple, en attendant que les données soient extraites du cache ou de la mémoire). Selon votre code, vous pouvez obtenir un ou quelques dizaines de pour cent d'utilisation supplémentaire du cœur, mais il est bien en deçà des performances d'un véritable cœur physique.
Andre Holzner

23

Cela vous donne le nombre de CPU hyperthreaded

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

Cela vous donne le nombre de CPU de la machine virtuelle

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

N'importe que si vous travaillez sur des machines virtuelles.


Pas vraiment. Comme indiqué, os.cpu_count()et multiprocessing.cpu_count()renverra le nombre de processeurs hyperthreadés, et non le nombre réel de processeurs physiques.
Christopher Barber

2
Oui. J'ai reformulé. C'est généralement # de cœurs x 2. Ce que je veux dire, c'est que si vous êtes sur une machine virtuelle, cela a créé 8 cœurs, mais votre machine hôte est à 20 cœurs physiquement, le premier ensemble de commandes vous donne 20, le deuxième ensemble de commandes vous donne 8.
yangliu2

21

multiprocessing.cpu_count()renverra le nombre de CPU logiques, donc si vous avez un CPU quad-core avec hyperthreading, il reviendra 8. Si vous voulez le nombre de CPU physiques, utilisez les liaisons python pour hwloc:

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

hwloc est conçu pour être portable sur différents OS et architectures.


Dans ce cas, je veux le nombre de CPU logiques (c'est-à-dire combien de threads dois-je démarrer si ce programme évolue vraiment bien), mais la réponse peut néanmoins être utile.
phihag

7
oupsutil.cpu_count(logical=False)
TimZaman

8

Impossible de comprendre comment ajouter au code ou répondre au message, mais voici la prise en charge de Jython que vous pouvez aborder avant d'abandonner:

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

7

Cela peut fonctionner pour ceux d'entre nous qui utilisent différents systèmes d'exploitation / systèmes, mais qui veulent tirer le meilleur parti de tous les mondes:

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

5

Vous pouvez également utiliser "joblib" à cet effet.

import joblib
print joblib.cpu_count()

Cette méthode vous donnera le nombre de processeurs dans le système. joblib doit cependant être installé. Plus d'informations sur joblib peuvent être trouvées ici https://pythonhosted.org/joblib/parallel.html

Alternativement, vous pouvez utiliser le package numexpr de python. Il a beaucoup de fonctions simples utiles pour obtenir des informations sur le processeur du système.

import numexpr as ne
print ne.detect_number_of_cores()

joblib utilise le module de multitraitement sous-jacent. Il est probablement préférable d'appeler directement au multitraitement pour cela.
ogrisel

1

Une autre option si vous n'avez pas Python 2.6:

import commands
n = commands.getoutput("grep -c processor /proc/cpuinfo")

2
Merci! Cela n'est disponible que sur Linux et déjà inclus dans ma réponse .
phihag
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.