Cara mengetahui jumlah CPU menggunakan python

537

Saya ingin tahu jumlah CPU pada mesin lokal menggunakan Python. Hasilnya harus berupa user/realkeluaran time(1)saat dipanggil dengan program yang khusus untuk pengguna-spasi yang optimal.

phihag
sumber
3
Anda harus mengingat cpusets (di Linux). Jika Anda menggunakan cpuset, solusi di bawah ini masih akan memberikan jumlah CPU nyata dalam sistem, bukan jumlah yang tersedia untuk proses Anda. /proc/<PID>/statusmemiliki beberapa baris yang memberitahu Anda jumlah CPU di cpuset saat ini: cari Cpus_allowed_list.
wpoely86

Jawaban:

854

Jika Anda memiliki python dengan versi> = 2.6, Anda cukup menggunakan

import multiprocessing

multiprocessing.cpu_count()

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

Nadia Alramli
sumber
4
multiprocessing juga didukung dalam 3.x
LittleByBlue
3
Saya ingin menambahkan bahwa ini tidak berfungsi di IronPython yang menimbulkan NotImplementedError.
Matthias
1
Ini memberikan jumlah CPU yang tersedia ... tidak digunakan oleh program!
amc
25
Pada Python 3.6.2 saya hanya bisa menggunakanos.cpu_count()
Achilles
4
Juga, seperti yang disebutkan di bawah ini, jumlah ini dapat mencakup CPU virtual "dirubah", yang mungkin bukan yang Anda inginkan jika Anda menjadwalkan tugas intensif CPU.
Christopher Barber
186

Jika Anda tertarik dengan jumlah prosesor yang tersedia untuk proses Anda saat ini, Anda harus memeriksa cpuset terlebih dahulu. Kalau tidak (atau jika cpuset tidak digunakan), multiprocessing.cpu_count()adalah cara untuk menggunakan Python 2.6 dan yang lebih baru. Metode berikut jatuh kembali ke beberapa metode alternatif di versi Python yang lebih lama:

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
sumber
Pada MacPro 1.0 yang menjalankan Ubuntu terbaru, pada Laptop HP yang menjalankan Debian baru-baru ini, dan pada eMachine lama yang menjalankan Ubuntu lama, cpus_disebabkan hasil dari /proc/self/statusmasing-masing adalah ff, f dan f --- sesuai dengan 8, 4 dan 4 dengan matematika Anda (benar). Namun sebenarnya jumlah CPU masing-masing adalah 4, 2 dan 1. Saya menemukan bahwa menghitung jumlah kemunculan kata "prosesor" di /proc/cpuinfomungkin merupakan cara yang lebih baik. (Atau apakah saya memiliki pertanyaan yang salah?)
Mike O'Connor
1
Dengan beberapa penelitian lebih lanjut --- jika itu dapat dikatakan "Googling" --- Saya menemukan dari penggunaan /proc/cpuinfoitu jika untuk salah satu daftar untuk setiap "prosesor" Anda mengalikan "saudara" dengan "inti cpu" Anda mendapatkan nomor "Cpus_allowed" Anda. Dan saya berpendapat bahwa saudara kandung mengacu pada hyper-threading, maka referensi Anda untuk "virtual". Tetapi faktanya tetap bahwa nomor "Cpus_allowed" Anda adalah 8 pada MacPro saya sedangkan multiprocessing.cpu_count()jawaban Anda adalah 4. Milik saya open('/proc/cpuinfo').read().count('processor')juga menghasilkan 4, jumlah inti fisik (dua prosesor dual-core).
Mike O'Connor
1
open('/proc/self/status').read()lupa untuk menutup file. Gunakan with open('/proc/self/status') as f: f.read()sebagai gantinya
timdiels
4
os.cpu_count()
goetzc
1
@ amcgregor Dalam hal ini dapat diterima, disepakati, hanya file menangani dibiarkan terbuka yang saya kira tidak masalah jika Anda tidak menulis daemon / proses yang berjalan lama; yang saya khawatir mungkin akan berakhir dengan menangani file OS terbuka maksimal. Ini lebih buruk ketika menulis ke file yang perlu dibaca lagi sebelum proses berakhir, tetapi itu tidak terjadi di sini jadi itu adalah titik diperdebatkan. Tetap merupakan ide yang baik untuk memiliki kebiasaan menggunakan withketika Anda menemukan kasus di mana Anda membutuhkannya.
timdiels
91

Pilihan lain adalah menggunakan psutilperpustakaan, yang selalu bermanfaat dalam situasi ini:

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

Ini harus bekerja pada platform apa pun yang didukung oleh psutil(Unix dan Windows).

Perhatikan bahwa dalam beberapa kesempatan multiprocessing.cpu_countdapat menaikkan beberapa NotImplementedErrorsaat psutilakan dapat memperoleh jumlah CPU. Ini hanya karena psutilpertama kali mencoba menggunakan teknik yang sama yang digunakan oleh multiprocessingdan, jika gagal, itu juga menggunakan teknik lain.

Bakuriu
sumber
4
Yang ini sangat bagus, mengingat metode yang digunakan memungkinkan untuk mengetahui apakah inti CPU adalah yang asli. psutil.cpu_count(logical = True)
Devilhunter
Hai @ Bakuriu, Apakah ada cara untuk mendapatkan jumlah inti cpu yang digunakan oleh proses tertentu menggunakan psutil?
saichand
1
@Devilhunter Pada Windows pada Intel i7-8700 saya psutil.cpu_count()memberikan 12 (ini adalah CPU 6-core dengan hyperthreading). Ini karena argumen default logicaladalah Benar, jadi Anda secara eksplisit perlu menulis psutil.cpu_count(logical = False)untuk mendapatkan jumlah Core fisik.
OscarVanL
52

Dalam Python 3.4+: os.cpu_count () .

multiprocessing.cpu_count()diimplementasikan dalam hal fungsi ini tetapi menimbulkan NotImplementedErrorjika os.cpu_count()kembali None("tidak dapat menentukan jumlah CPU").

jfs
sumber
4
Lihat juga dokumentasi cpu_count. len(os.sched_getaffinity(0))mungkin lebih baik, tergantung tujuannya.
Albert
1
@Albert ya, jumlah CPU dalam sistem (- os.cpu_count()apa yang diminta OP) mungkin berbeda dari jumlah CPU yang tersedia untuk proses saat ini ( os.sched_getaffinity(0)).
jfs
Aku tahu. Saya hanya ingin menambahkan itu untuk pembaca lain, yang mungkin ketinggalan perbedaan ini, untuk mendapatkan gambar yang lebih lengkap dari mereka.
Albert
1
Juga: os.sched_getaffinity(0)ini tidak tersedia di BSD, sehingga penggunaan os.cpu_count()diperlukan (tanpa perpustakaan eksternal lainnya, yaitu).
Cometsong
1
Perlu dicatat os.sched_getaffinity tampaknya tidak tersedia di Windows.
manu3d
47

len(os.sched_getaffinity(0)) adalah apa yang biasanya Anda inginkan

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

os.sched_getaffinity(0)(ditambahkan dalam Python 3) mengembalikan set CPU yang tersedia mengingat sched_setaffinitypanggilan sistem Linux , yang membatasi CPU mana proses dan anak-anaknya dapat berjalan.

0artinya mendapatkan nilai untuk proses saat ini. Fungsi mengembalikan a set()dari CPU yang diizinkan, sehingga perlu len().

multiprocessing.cpu_count() di sisi lain hanya mengembalikan jumlah total CPU fisik.

Perbedaan ini sangat penting karena sistem manajemen cluster tertentu seperti Platform LSF membatasi penggunaan CPU dengan pekerjaan sched_getaffinity.

Oleh karena itu, jika Anda menggunakan multiprocessing.cpu_count(), skrip Anda mungkin mencoba menggunakan lebih banyak core daripada yang tersedia, yang dapat menyebabkan kelebihan muatan dan batas waktu.

Kita dapat melihat perbedaan secara konkret dengan membatasi afinitas dengan tasksetutilitas.

Sebagai contoh, jika saya membatasi Python hanya 1 core (core 0) di sistem 16 core saya:

taskset -c 0 ./main.py

dengan skrip uji:

main.py

#!/usr/bin/env python3

import multiprocessing
import os

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

maka outputnya adalah:

16
1

nproc namun demikian menghargai afinitas secara default dan:

taskset -c 0 nproc

output:

1

dan man nprocmembuatnya cukup eksplisit:

cetak jumlah unit pemrosesan yang tersedia

nprocmemiliki --alltanda untuk kasus yang kurang umum yang ingin Anda peroleh hitungan CPU fisik:

taskset -c 0 nproc --all

Satu-satunya downside dari metode ini adalah bahwa ini tampaknya hanya UNIX. Saya kira Windows harus memiliki API afinitas yang sama, mungkin SetProcessAffinityMask, jadi saya bertanya-tanya mengapa itu belum porting. Tapi saya tidak tahu apa-apa tentang Windows.

Diuji dalam Ubuntu 16.04, Python 3.5.2.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
3
Hanya tersedia di Unix.
Christopher Barber
@ChristopherBarber terima kasih atas informasinya, ditambahkan ke jawabannya.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
34

Jika Anda ingin mengetahui jumlah core fisik (bukan core hyperthreaded virtual), berikut adalah solusi platform independen:

psutil.cpu_count(logical=False)

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

Perhatikan bahwa nilai default untuk logicaladalah True, jadi jika Anda ingin memasukkan core yang dapat di hiphread, Anda dapat menggunakan:

psutil.cpu_count()

Ini akan memberikan nomor yang sama dengan os.cpu_count()dan multiprocessing.cpu_count(), tidak ada yang memiliki logicalargumen kata kunci.

Davoud Taghawi-Nejad
sumber
4
Apa perbedaan antara CPU logis dan bukan yang logis? di laptop saya: psutil.cpu_count(logical=False) #4 psutil.cpu_count(logical=True) #8danmultiprocessing.cpu_count() #8
user305883
1
@ user305883 dengan anggapan Anda memiliki CPU x86, berarti Anda memiliki hiphreading pada mesin ini, yaitu setiap inti fisik berhubungan dengan dua hyperthreads (core 'logis'). Hyperthreading memungkinkan inti fisik yang akan digunakan untuk menjalankan instruksi dari utas B ketika bagian-bagiannya menganggur untuk utas A (misalnya menunggu data diambil dari cache atau memori). Bergantung pada kode Anda, Anda bisa mendapatkan satu atau beberapa puluh persen dari pemanfaatan inti tambahan tetapi jauh di bawah kinerja inti fisik nyata.
Andre Holzner
23

Ini memberi Anda jumlah CPU hyperthreaded

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

Ini memberi Anda jumlah CPU mesin virtual

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

Hanya masalah jika Anda bekerja pada VM.

yangliu2
sumber
Tidak juga. Seperti dicatat, os.cpu_count()dan multiprocessing.cpu_count()akan mengembalikan jumlah cpu yang di-hiphread, bukan jumlah cpu fisik yang sebenarnya.
Christopher Barber
2
Iya. Saya menulis ulang. Ini biasanya # dari inti x 2. Yang saya maksud adalah bahwa jika Anda menggunakan mesin virtual, yang mengukir 8 inti, tetapi mesin host Anda adalah 20 inti secara fisik, set perintah pertama memberi Anda 20, set perintah kedua memberi Anda 8.
yangliu2
21

multiprocessing.cpu_count()akan mengembalikan jumlah CPU logis, jadi jika Anda memiliki CPU quad-core dengan hyperthreading, itu akan kembali 8. Jika Anda ingin jumlah CPU fisik, gunakan binding python ke hwloc:

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

hwloc dirancang untuk portabel di seluruh OS dan arsitektur.

Douglas B. Staple
sumber
Dalam hal ini, saya ingin jumlah CPU logis (yaitu berapa banyak utas yang harus saya mulai jika program ini berskala sangat baik), tetapi jawabannya mungkin tetap membantu.
phihag
7
ataupsutil.cpu_count(logical=False)
TimZaman
8

Tidak dapat menemukan cara menambahkan kode atau membalas pesan, tetapi inilah dukungan untuk jython yang dapat Anda tempel sebelum menyerah:

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

Ini mungkin bekerja untuk kita yang menggunakan os / sistem berbeda, tetapi ingin mendapatkan yang terbaik dari semua dunia:

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

Anda juga dapat menggunakan "joblib" untuk tujuan ini.

import joblib
print joblib.cpu_count()

Metode ini akan memberi Anda jumlah CPU dalam sistem. joblib perlu diinstal. Informasi lebih lanjut tentang joblib dapat ditemukan di sini https://pythonhosted.org/joblib/parallel.html

Atau Anda dapat menggunakan paket numexpr dari python. Ini memiliki banyak fungsi sederhana yang membantu untuk mendapatkan informasi tentang cpu sistem.

import numexpr as ne
print ne.detect_number_of_cores()
amit12690
sumber
joblib menggunakan modul multiprosesor yang mendasarinya. Mungkin lebih baik menelepon langsung ke multi-pemrosesan untuk ini.
ogrisel
1

Opsi lain jika Anda tidak memiliki Python 2.6:

import commands
n = commands.getoutput("grep -c processor /proc/cpuinfo")
Alkero
sumber
2
Terima kasih! Ini hanya tersedia di Linux, dan sudah termasuk dalam jawaban saya .
phihag