Come scoprire il numero di CPU usando Python


537

Voglio sapere il numero di CPU sul computer locale usando Python. Il risultato dovrebbe essere user/reall'output di time(1)quando viene chiamato con un programma di solo spazio utente in scala ottimale.


3
Dovresti tenere a mente cpusets (in Linux). Se sei in un cpuset, le soluzioni seguenti forniranno comunque il numero di CPU reali nel sistema, non il numero disponibile per il tuo processo. /proc/<PID>/statusha alcune righe che indicano il numero di CPU nell'attuale cpuset: cerca Cpus_allowed_list.
wpoely86,

Risposte:


854

Se hai Python con una versione> = 2.6 puoi semplicemente usare

import multiprocessing

multiprocessing.cpu_count()

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


4
il multiprocessing è supportato anche in 3.x
LittleByBlue,

3
Voglio aggiungere che questo non funziona in IronPython che genera un NotImplementedError.
Matthias,

1
Questo fornisce il numero di CPU disponibili ... non utilizzate dal programma!
amc

25
Su Python 3.6.2 ho potuto usare soloos.cpu_count()
Achille l'

4
Inoltre, come indicato di seguito, questo conteggio può includere cpus hyperthreaded "virtuale", che potrebbe non essere quello che desideri se stai pianificando attività ad alta intensità di cpu.
Christopher Barber,

186

Se sei interessato al numero di processori disponibili per il tuo processo attuale, devi prima controllare cpuset . Altrimenti (o se cpuset non è in uso), multiprocessing.cpu_count()è la strada da percorrere in Python 2.6 e successive. Il seguente metodo ricade su un paio di metodi alternativi nelle versioni precedenti di 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')

Su un MacPro 1,0 che esegue l'ultimo Ubuntu, su un laptop HP che esegue un Debian recente e su un vecchio eMachine che esegue un vecchio Ubuntu, i risultati cpus_ concessi /proc/self/statussono rispettivamente ff, f e f --- corrispondenti a 8, 4 e 4 secondo la tua (corretta) matematica. Tuttavia, i numeri effettivi di CPU sono rispettivamente 4, 2 e 1. Trovo che contare il numero di occorrenze della parola "processore" /proc/cpuinfopotrebbe essere il modo migliore di procedere. (O ho la domanda sbagliata?)
Mike O'Connor,

1
Con qualche ulteriore ricerca --- se si può dire di "Googling" --- Trovo dall'uso /proc/cpuinfoche se per uno degli elenchi per ogni "processore" moltiplichi i "fratelli" per i "core della CPU" ottieni il tuo numero "Cpus_allowed". E capisco che i fratelli si riferiscono all'hyper-threading, da cui il tuo riferimento a "virtuale". Ma resta il fatto che il tuo numero "Cpus_allowed" è 8 sul mio MacPro mentre la tua multiprocessing.cpu_count()risposta è 4. Il mio open('/proc/cpuinfo').read().count('processor')produce anche 4, il numero di core fisici (due processori dual-core).
Mike O'Connor,

1
open('/proc/self/status').read()dimentica di chiudere il file. Usa with open('/proc/self/status') as f: f.read()invece
timdiels

4
os.cpu_count()
Goetzc,

1
@amcgregor In questo caso è accettabile, d'accordo, solo gli handle di file vengono lasciati aperti, il che immagino sia ok se non stai scrivendo un demone / processo di lunga esecuzione; che temo potrebbe finire col colpire un massimo di handle di file aperti del sistema operativo. È peggio quando si scrive su un file che deve essere letto di nuovo prima che il processo finisca, ma non è questo il caso, quindi è un punto controverso. Comunque è una buona idea avere l'abitudine di usarlo withper quando incontri un caso in cui ne hai bisogno.
timdiels,

91

Un'altra opzione è quella di utilizzare la psutillibreria, che risulta sempre utile in queste situazioni:

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

Questo dovrebbe funzionare su qualsiasi piattaforma supportata da psutil(Unix e Windows).

Si noti che in alcune occasioni multiprocessing.cpu_countpotrebbe aumentare un NotImplementedErrorpo ' psutilsarà possibile ottenere il numero di CPU. Questo semplicemente perché psutilprima cerca di usare le stesse tecniche usate multiprocessinge, se falliscono, usa anche altre tecniche.


4
Questo è davvero buono, considerando che il metodo utilizzato consente di scoprire se i core della CPU sono logici o fisici. psutil.cpu_count(logical = True)
Devilhunter,

Ciao @Bakuriu, C'è un modo per ottenere il numero di core della CPU utilizzati da un processo specifico usando psutil?
saichand,

1
@Devilhunter Su Windows sul mio Intel i7-8700 psutil.cpu_count()dà 12 (è una CPU a 6 core con hyperthreading). Questo perché l'argomento predefinito di logicalè True, quindi è necessario scrivere esplicitamente psutil.cpu_count(logical = False)per ottenere il numero di core fisici.
OscarVanL

52

In Python 3.4+: os.cpu_count () .

multiprocessing.cpu_count()è implementato in termini di questa funzione ma genera NotImplementedErrorse os.cpu_count()restituisce None("impossibile determinare il numero di CPU").


4
Vedi anche la documentazione di cpu_count. len(os.sched_getaffinity(0))potrebbe essere migliore, a seconda dello scopo.
Albert,

1
@Albert sì, il numero di CPU nel sistema ( os.cpu_count()—che cosa chiede OP) può differire dal numero di CPU disponibili per il processo corrente ( os.sched_getaffinity(0)).
jfs,

Lo so. Volevo solo aggiungere questo per altri lettori, che potrebbero perdere questa differenza, per ottenere un'immagine più completa da loro.
Albert,

1
Inoltre: nonos.sched_getaffinity(0) è disponibile su BSD, quindi è necessario l'uso di (senza altra libreria esterna, cioè). os.cpu_count()
Cometsong,

1
Va notato che os.sched_getaffinity non sembra essere disponibile su Windows.
manu3d,

47

len(os.sched_getaffinity(0)) è quello che di solito vuoi

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

os.sched_getaffinity(0)(aggiunto in Python 3) restituisce il set di CPU disponibili considerando la sched_setaffinitychiamata di sistema Linux , che limita le CPU su cui è possibile eseguire un processo e i suoi figli.

0significa ottenere il valore per il processo corrente. La funzione restituisce una set()delle CPU consentite, quindi la necessità dilen() .

multiprocessing.cpu_count() d'altra parte restituisce solo il numero totale di CPU fisiche.

La differenza è particolarmente importante perché alcuni sistemi di gestione dei cluster come Platform LSF limitano l'utilizzo della CPU del lavoro sched_getaffinity.

Pertanto, se si utilizza multiprocessing.cpu_count() , lo script potrebbe tentare di utilizzare un numero di core maggiore rispetto a quello disponibile, il che potrebbe causare sovraccarichi e timeout.

Possiamo vedere concretamente la differenza limitando l'affinità con il taskset utilità.

Ad esempio, se restringo Python a un solo core (core 0) nel mio sistema a 16 core:

taskset -c 0 ./main.py

con lo script di test:

main.py

#!/usr/bin/env python3

import multiprocessing
import os

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

quindi l'output è:

16
1

nproc tuttavia rispetta l'affinità di default e:

taskset -c 0 nproc

uscite:

1

e lo man nprocrende abbastanza esplicito:

stampa il numero di unità di elaborazione disponibili

nprocha il --allflag per il caso meno comune in cui si desidera ottenere il conteggio fisico della CPU:

taskset -c 0 nproc --all

L'unico aspetto negativo di questo metodo è che questo sembra essere solo UNIX. Suppongo che Windows debba avere un'API di affinità simile, possibilmente SetProcessAffinityMask, quindi mi chiedo perché non sia stato portato. Ma non so nulla di Windows.

Testato in Ubuntu 16.04, Python 3.5.2.


3
Disponibile solo su Unix.
Christopher Barber,

@ChristopherBarber grazie per le informazioni, aggiunte alla risposta.
Ciro Santilli 7 冠状 病 六四 事件 法轮功

34

Se vuoi conoscere il numero di core fisici (non core hyperthreaded virtuali), ecco una soluzione indipendente dalla piattaforma:

psutil.cpu_count(logical=False)

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

Si noti che il valore predefinito per logicalè True, quindi se si desidera includere core hyperthreaded è possibile utilizzare:

psutil.cpu_count()

Questo darà lo stesso numero di os.cpu_count()e multiprocessing.cpu_count(), nessuno dei quali ha l' logicalargomento keyword.


4
Qual è la differenza tra una CPU logica e non una CPU logica? sul mio laptop: psutil.cpu_count(logical=False) #4 psutil.cpu_count(logical=True) #8emultiprocessing.cpu_count() #8
user305883

1
@ user305883 supponendo che tu abbia una CPU x86, hai hyperthreading su questa macchina, cioè ogni core fisico corrisponde a due hyperthread (core 'logici'). L'hyperthreading consente di utilizzare il core fisico per eseguire le istruzioni dal thread B quando parti di esso sono inattive per il thread A (ad esempio, in attesa che i dati vengano recuperati dalla cache o dalla memoria). A seconda del codice si possono ottenere una o poche decine di percentuali di utilizzo aggiuntivo del core, ma è molto inferiore alle prestazioni di un vero core fisico.
Andre Holzner,

23

Questi ti danno il conteggio della CPU hyperthreaded

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

Questi ti danno il conteggio della CPU della macchina virtuale

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

Importa solo se lavori su VM.


Non proprio. Come notato, os.cpu_count()e multiprocessing.cpu_count()restituirà i conteggi della CPU hyperthreaded, non il conteggio effettivo della CPU fisica.
Christopher Barber,

2
Sì. Ho riformulato. In genere è il numero di core x 2. Quello che voglio dire è che se sei su una macchina virtuale, questo ha scavato 8 core, ma la tua macchina host è fisicamente 20 core, il primo set di comandi ti dà 20, il secondo set di comandi ti dà 8.
yangliu2

21

multiprocessing.cpu_count()restituirà il numero di CPU logiche, quindi se si dispone di una CPU quad-core con hyperthreading, verrà restituito 8. Se vuoi il numero di CPU fisiche, usa i collegamenti python per hwloc:

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

hwloc è progettato per essere portatile su sistemi operativi e architetture.


In questo caso, desidero il numero di CPU logiche (ovvero quanti thread dovrei iniziare se questo programma si ridimensiona davvero bene), ma la risposta può essere comunque utile.
phihag,

7
oppurepsutil.cpu_count(logical=False)
TimZaman,

8

Non riesco a capire come aggiungere al codice o rispondere al messaggio, ma ecco il supporto per jython che puoi seguire prima di rinunciare:

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

7

Questo potrebbe funzionare per quelli di noi che usano diversi sistemi operativi, ma vogliono ottenere il meglio da tutti i mondi:

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

5

A tale scopo è anche possibile utilizzare "joblib".

import joblib
print joblib.cpu_count()

Questo metodo ti darà il numero di cpus nel sistema. joblib deve essere installato però. Maggiori informazioni su joblib sono disponibili qui https://pythonhosted.org/joblib/parallel.html

In alternativa puoi usare il pacchetto numexpr di python. Ha molte funzioni semplici utili per ottenere informazioni sulla cpu di sistema.

import numexpr as ne
print ne.detect_number_of_cores()

joblib utilizza il modulo multiprocessing sottostante. Probabilmente è meglio chiamare direttamente in multiprocessing per questo.
Ogrisel,

1

Un'altra opzione se non hai Python 2.6:

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

2
Grazie! Questo è disponibile solo su Linux e già incluso nella mia risposta .
phihag,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.