Jak sprawdzić liczbę procesorów za pomocą Pythona


537

Chcę poznać liczbę procesorów na komputerze lokalnym za pomocą Pythona. Wynik powinien być taki sam, user/realjak w time(1)przypadku wywołania za pomocą optymalnie skalowanego programu przeznaczonego tylko dla użytkowników.


3
Powinieneś pamiętać o cpusets (w Linuksie). Jeśli korzystasz z procesora, poniższe rozwiązania nadal podadzą liczbę rzeczywistych procesorów w systemie, a nie liczbę dostępną dla twojego procesu. /proc/<PID>/statusma kilka wierszy informujących o liczbie procesorów w bieżącym procesorze: wyszukaj Cpus_allowed_list.
wpoely86,

Odpowiedzi:


854

Jeśli masz Pythona w wersji> = 2.6, możesz po prostu użyć

import multiprocessing

multiprocessing.cpu_count()

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


4
wieloprocesowość jest również obsługiwana w wersji 3.x
LittleByBlue,

3
Chcę dodać, że to nie działa w IronPython, który podnosi NotImplementedError.
Matthias

1
Daje to liczbę dostępnych procesorów ... nieużywanych przez program!
amc

25
W Pythonie 3.6.2 mogłem używać tylkoos.cpu_count()
Achilles

4
Ponadto, jak zauważono poniżej, liczba ta może obejmować „wirtualny” procesor hipertekstowy, co może nie być tym, czego oczekujesz, jeśli planujesz zadania wymagające dużej mocy obliczeniowej.
Christopher Barber

185

Jeśli interesuje Cię liczba procesorów dostępnych dla bieżącego procesu, musisz najpierw sprawdzić cpuset . W przeciwnym razie (lub jeśli cpuset nie jest używany), multiprocessing.cpu_count()jest to droga do przejścia w Pythonie 2.6 i nowszych. Następująca metoda odwołuje się do kilku alternatywnych metod w starszych wersjach Pythona:

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

Na MacPro 1,0 z najnowszym Ubuntu, na laptopie HP z najnowszym Debianem, a na starym eMachine ze starym Ubuntu, wyniki cpus_allowed /proc/self/statussą odpowiednio ff, f i f --- odpowiadające 8, 4 i 4 według (poprawnej) matematyki. Jednak rzeczywista liczba procesorów wynosi odpowiednio 4, 2 i 1. Uważam, że policzenie liczby wystąpień słowa „procesor” /proc/cpuinfomoże być lepszym sposobem. (Czy mam błędne pytanie?)
Mike O'Connor,

1
Po kilku dalszych badaniach --- czy można to powiedzieć o „googlowaniu” --- po zastosowaniu tego /proc/cpuinfostwierdzam, że dla dowolnej z list dla każdego „procesora” mnożymy „rodzeństwo” przez „rdzenie procesora” dostaniesz swój numer „Cpus_allowed”. I rozumiem, że rodzeństwo odnosi się do hiperwątkowości, stąd wasze odniesienie do „wirtualnego”. Ale faktem jest, że twoja liczba „Cpus_allowed” wynosi 8 na moim MacPro, podczas gdy twoja multiprocessing.cpu_count()odpowiedź to 4. Moje własne open('/proc/cpuinfo').read().count('processor')produkują również 4, czyli liczbę rdzeni fizycznych (dwa dwurdzeniowe procesory).
Mike O'Connor,

1
open('/proc/self/status').read()zapomina zamknąć plik. with open('/proc/self/status') as f: f.read()Zamiast tego użyj
timdiels,

4
os.cpu_count()
goetzc

1
@amcgregor W tym przypadku jest to dopuszczalne, uzgodnione, po prostu pozostawienie otwartych uchwytów plików, które, jak sądzę, jest w porządku, jeśli nie piszesz długo działającego demona / procesu; Obawiam się, że może trafić do maksymalnie otwartych uchwytów plików systemu operacyjnego. Gorzej jest, gdy zapisujemy do pliku, który musi zostać ponownie odczytany przed zakończeniem procesu, ale tutaj tak nie jest, więc to kwestia sporna. Nadal dobrym pomysłem jest nawyk używania, withgdy napotkasz przypadek, w którym go potrzebujesz.
timdiels

91

Inną opcją jest użycie psutil biblioteki, która zawsze okazuje się przydatna w następujących sytuacjach:

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

Powinno to działać na dowolnej platformie obsługiwanej przez psutil(Unix i Windows).

Należy pamiętać, że w niektórych przypadkach multiprocessing.cpu_countmoże wzrosnąć przez pewien NotImplementedErrorczas psutilbędzie w stanie uzyskać liczbę procesorów. Dzieje się tak po prostu dlatego, że psutilnajpierw próbuje zastosować te same techniki, których używa, multiprocessinga jeśli te zawiodą, stosuje również inne techniki.


4
Ten jest naprawdę dobry, biorąc pod uwagę, że zastosowana metoda pozwala dowiedzieć się, czy rdzenie procesora są logiczne lub fizyczne. psutil.cpu_count(logical = True)
Devilhunter

Cześć @ Bakuriu, Czy jest jakiś sposób, aby uzyskać liczbę rdzeni procesora używanych przez określony proces przy użyciu psutil?
saichand

@Devilhunter W systemie Windows na moim procesorze Intel i7-8700 psutil.cpu_count()daje 12 (jest to 6-rdzeniowy procesor z hyperthreading). Wynika to z tego, że domyślnym argumentem logicaljest Prawda, więc musisz jawnie napisać, psutil.cpu_count(logical = False)aby uzyskać liczbę fizycznych rdzeni.
OscarVanL

52

W Python 3.4+: os.cpu_count () .

multiprocessing.cpu_count()jest zaimplementowany w kategoriach tej funkcji, ale podnosi się, NotImplementedErrorjeśli os.cpu_count()zwraca None(„nie można określić liczby procesorów”).


4
Zobacz także dokumentację cpu_count. len(os.sched_getaffinity(0))może być lepiej, w zależności od celu.
Albert,

1
@Albert tak, liczba procesorów w systemie (- o co os.cpu_count()prosi OP) może różnić się od liczby procesorów dostępnych dla bieżącego procesu ( os.sched_getaffinity(0)).
jfs

Wiem. Chciałem tylko dodać to dla innych czytelników, którzy mogą przegapić tę różnicę, aby uzyskać od nich pełniejszy obraz.
Albert,

1
Ponadto: nieos.sched_getaffinity(0) jest dostępny w BSD, więc użycie jest wymagane (bez innej biblioteki zewnętrznej). os.cpu_count()
Cometsong

1
Należy zauważyć, że os.sched_getaffinity nie wydaje się być dostępny w systemie Windows.
manu3d

47

len(os.sched_getaffinity(0)) jest tym, czego zwykle chcesz

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

os.sched_getaffinity(0)(dodany w Pythonie 3) zwraca zestaw dostępnych procesorów, biorąc pod uwagę sched_setaffinitywywołanie systemowe Linux , które ogranicza procesory, na których proces i jego potomne mogą działać.

0oznacza uzyskanie wartości dla bieżącego procesu. Funkcja zwraca a set()dozwolonych procesorów, stąd potrzeba len().

multiprocessing.cpu_count() z drugiej strony po prostu zwraca całkowitą liczbę fizycznych procesorów.

Różnica jest szczególnie ważna, ponieważ niektóre systemy zarządzania klastrami, takie jak Platform LSF, ograniczają użycie procesora zadaniasched_getaffinity .

Dlatego jeśli używasz multiprocessing.cpu_count() , twój skrypt może próbować użyć znacznie większej liczby rdzeni, niż ma dostępnych, co może prowadzić do przeciążenia i przekroczenia limitu czasu.

Widzimy różnicę konkretnie, ograniczając powinowactwo z taskset użytecznością.

Na przykład, jeśli ograniczę Pythona do 1 rdzenia (0 rdzenia) w moim 16-rdzeniowym systemie:

taskset -c 0 ./main.py

ze skryptem testowym:

main.py

#!/usr/bin/env python3

import multiprocessing
import os

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

następnie dane wyjściowe to:

16
1

nproc jednak domyślnie szanuje powinowactwo i:

taskset -c 0 nproc

wyjścia:

1

i man nprocczyni to całkiem wyraźnym:

wydrukuj liczbę dostępnych jednostek przetwarzania

nprocma --allflagę dla rzadszego przypadku, w którym chcesz uzyskać fizyczną liczbę procesorów:

taskset -c 0 nproc --all

Jedynym minusem tej metody jest to, że wydaje się, że jest to tylko UNIX. Podejrzewam, że Windows musi mieć podobny interfejs API powinowactwa SetProcessAffinityMask, więc zastanawiam się, dlaczego nie został przeniesiony. Ale nic nie wiem o systemie Windows.

Testowane w Ubuntu 16.04, Python 3.5.2.


3
Dostępne tylko w systemie Unix.
Christopher Barber

@ChristopherBarber dzięki za informacje, dodane do odpowiedzi.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

33

niezależny od platformy:

psutil.cpu_count (logiczne = Fałsz)

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


4
Jaka jest różnica między logicznym procesorem, a nie logicznym? na moim laptopie: psutil.cpu_count(logical=False) #4 psutil.cpu_count(logical=True) #8imultiprocessing.cpu_count() #8
user305883

1
@ user305883 przy założeniu, że masz procesor x86, masz hyperthreading na tym komputerze, tzn. każdy fizyczny rdzeń odpowiada dwóm hyperthreads (rdzeniom logicznym). Hyperthreading pozwala na wykorzystanie rdzenia fizycznego do wykonywania instrukcji z wątku B, gdy jego części są bezczynne dla wątku A (np. Oczekiwanie na pobranie danych z pamięci podręcznej lub pamięci). W zależności od kodu można uzyskać jeden lub kilkadziesiąt procent dodatkowego wykorzystania rdzenia, ale jest to znacznie poniżej wydajności prawdziwego rdzenia fizycznego.
Andre Holzner,

23

Dają ci liczbę procesorów hyperthreaded

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

Dają ci liczbę procesorów maszyny wirtualnej

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

Ma to znaczenie tylko, jeśli pracujesz na maszynach wirtualnych.


Nie całkiem. Jak wspomniano, os.cpu_count()i multiprocessing.cpu_count()zwróci liczbę procesorów z hiperwątkiem, a nie rzeczywistą fizyczną liczbę procesorów.
Christopher Barber

2
Tak. Przeredagowałem. Zazwyczaj jest to liczba rdzeni x 2. Mam na myśli to, że jeśli jesteś na maszynie wirtualnej, to wykroiłem 8 rdzeni, ale twoja maszyna hosta ma 20 rdzeni fizycznie, pierwszy zestaw poleceń daje ci 20, drugi zestaw poleceń daje ci 8.
yangliu2,

21

multiprocessing.cpu_count() zwróci liczbę logicznych procesorów, więc jeśli masz czterordzeniowy procesor z hyperthreading, zwróci 8 . Jeśli chcesz mieć liczbę fizycznych procesorów, użyj hwloc:

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

hwloc jest zaprojektowany tak, aby był przenośny w różnych systemach operacyjnych i architekturach.


W tym przypadku chcę liczbę procesorów logicznych (tj. Ile wątków powinienem uruchomić, jeśli program ten skaluje się naprawdę dobrze), ale odpowiedź może być pomocna.
phihag

7
lubpsutil.cpu_count(logical=False)
TimZaman

8

Nie mogę wymyślić, jak dodać do kodu lub odpowiedzieć na wiadomość, ale oto wsparcie dla Jython, które możesz wprowadzić przed rezygnacją:

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

7

Może to działać dla tych z nas, którzy używają różnych systemów operacyjnych, ale chcą uzyskać to, co najlepsze ze wszystkich światów:

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

5

W tym celu możesz również użyć „joblib”.

import joblib
print joblib.cpu_count()

Ta metoda da ci liczbę procesorów w systemie. Joblib musi być jednak zainstalowany. Więcej informacji na temat joblib można znaleźć tutaj https://pythonhosted.org/joblib/parallel.html

Alternatywnie możesz użyć pakietu numexpr Pythona. Ma wiele prostych funkcji pomocnych w uzyskiwaniu informacji o procesorze systemowym.

import numexpr as ne
print ne.detect_number_of_cores()

joblib używa bazowego modułu wieloprocesowego. Prawdopodobnie najlepiej jest w tym celu bezpośrednio włączyć proces wieloprocesowy.
ogrisel

1

Inna opcja, jeśli nie masz języka Python 2.6:

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

2
Dzięki! Jest to jednak dostępne tylko w systemie Linux i już zawarte w mojej odpowiedzi .
phihag
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.