วิธีค้นหาจำนวนของ CPU ที่ใช้ python


537

ฉันต้องการทราบจำนวนซีพียูในเครื่องท้องถิ่นโดยใช้ Python ผลลัพธ์ควรuser/realเป็นเอาต์พุตโดยtime(1)เมื่อถูกเรียกด้วยการปรับขนาดโปรแกรม userspace-only อย่างเหมาะสมที่สุด


3
คุณควรจำ cpusets (ใน Linux) หากคุณอยู่ใน cpuset โซลูชั่นด้านล่างจะยังคงให้จำนวน CPU จริงในระบบไม่ใช่จำนวนที่กระบวนการของคุณสามารถใช้ได้ /proc/<PID>/statusมีเส้นบางที่บอกให้คุณจำนวนซีพียูใน cpuset ปัจจุบัน: Cpus_allowed_listมองหา
wpoely86

คำตอบ:


854

หากคุณมี python พร้อมกับรุ่น> = 2.6 คุณสามารถใช้

import multiprocessing

multiprocessing.cpu_count()

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


4
รองรับการประมวลผลหลายตัวใน 3.x
LittleByBlue

3
ฉันต้องการเพิ่มว่าสิ่งนี้ไม่ทำงานใน IronPython ซึ่งทำให้เกิด NotImplementedError
Matthias

1
นี่ทำให้จำนวนของ CPU ที่พร้อมใช้งาน ... ไม่ได้ถูกใช้โดยโปรแกรม
amc

25
ใน Python 3.6.2 ฉันสามารถใช้ได้เท่านั้นos.cpu_count()
Achilles

4
นอกจากนี้ตามที่ระบุไว้ด้านล่างการนับนี้สามารถรวมซีพียูไฮเปอร์เธรด "เสมือน" ซึ่งอาจไม่ใช่สิ่งที่คุณต้องการหากคุณกำลังกำหนดตารางงานที่ต้องใช้งาน cpu มาก
คริสโตเฟอร์ตัดผม

186

หากคุณสนใจจำนวนโปรเซสเซอร์ที่มีอยู่สำหรับกระบวนการปัจจุบันของคุณคุณต้องตรวจสอบcpusetก่อน มิฉะนั้น (หรือหาก cpuset ไม่ได้ใช้งาน) multiprocessing.cpu_count()เป็นวิธีที่จะใช้งานใน Python 2.6 และใหม่กว่า วิธีการต่อไปนี้กลับไปเป็นวิธีการสองทางใน 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')

ใน MacPro 1,0 ที่รัน Ubuntu ล่าสุดบนแล็ปท็อป HP ที่ใช้ Debian ล่าสุดและบน eMachine รุ่นเก่าที่ใช้ Ubuntu เก่าผลลัพธ์ cpus_allowed ของ/proc/self/statusจะเรียงตามลำดับ ff, f และ f --- สอดคล้องกับ 8, 4 และ 4 โดยคณิตศาสตร์ของคุณ (ถูกต้อง) อย่างไรก็ตามจำนวน CPU ที่แท้จริงตามลำดับคือ 4, 2 และ 1 ฉันพบว่าการนับจำนวนที่เกิดขึ้นของคำว่า "โปรเซสเซอร์" ใน/proc/cpuinfoอาจเป็นวิธีที่ดีกว่า (หรือฉันมีคำถามผิดหรือเปล่า?)
Mike O'Connor

1
ด้วยการวิจัยเพิ่มเติม - หากสามารถกล่าวได้ว่า "Googling" --- ฉันค้นหาจากการใช้/proc/cpuinfoสิ่งนั้นหากสำหรับรายการใดรายการหนึ่งสำหรับ "ตัวประมวลผล" แต่ละตัวคุณคูณ "พี่น้อง" ด้วย "cpu cores" คุณได้รับหมายเลข "Cpus_allowed" ของคุณ และฉันรวบรวมว่าพี่น้องอ้างถึงไฮเปอร์เธรดดังนั้นการอ้างอิงของคุณถึง "เสมือน" แต่ความจริงก็คือตัวเลข "Cpus_allowed" ของคุณคือ 8 ใน MacPro ของฉันในขณะที่multiprocessing.cpu_count()คำตอบของคุณคือ 4 ฉันเองopen('/proc/cpuinfo').read().count('processor')ก็สร้าง 4 จำนวนแกนประมวลผลทางกายภาพ (โปรเซสเซอร์ดูอัลคอร์สองตัว)
Mike O'Connor

1
open('/proc/self/status').read()ลืมที่จะปิดไฟล์ ใช้with open('/proc/self/status') as f: f.read()แทน
timdiels

4
os.cpu_count()
goetzc

1
@amcgregor ในกรณีนี้เป็นที่ยอมรับตกลงเพียงจัดการไฟล์ที่เปิดทิ้งไว้ซึ่งฉันเดาว่าก็โอเคถ้าคุณไม่ได้เขียน daemon / กระบวนการที่ใช้เวลานาน ซึ่งฉันเกรงว่าท้ายที่สุดจะสามารถกดปุ่มเปิดไฟล์ได้สูงสุดของ OS มันแย่กว่าเมื่อเขียนไฟล์ที่ต้องอ่านอีกครั้งก่อนที่กระบวนการจะจบลง แต่นั่นไม่ใช่กรณีที่นี่เพื่อเป็นจุดที่สงสัย ยังเป็นความคิดที่ดีที่จะมีนิสัยใช้withเมื่อคุณพบกรณีที่คุณต้องการ
timdiels

91

อีกทางเลือกหนึ่งคือการใช้psutilห้องสมุดซึ่งจะเป็นประโยชน์ในสถานการณ์เหล่านี้:

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

สิ่งนี้จะทำงานได้บนทุกแพลตฟอร์มที่รองรับโดยpsutil(Unix และ Windows)

โปรดทราบว่าในบางโอกาสmultiprocessing.cpu_countอาจเพิ่มสักNotImplementedErrorครู่psutilเพื่อให้ได้จำนวนของ CPU นี่เป็นเพียงเพราะpsutilครั้งแรกพยายามที่จะใช้เทคนิคเดียวกันกับที่ใช้โดยmultiprocessingและหากล้มเหลวก็จะใช้เทคนิคอื่น ๆ


4
อันนี้ดีจริงๆเมื่อพิจารณาว่าวิธีการที่ใช้ช่วยให้ค้นพบว่าแกนประมวลผลของ CPU เป็นวัตถุทางกายภาพของตรรกะ psutil.cpu_count(logical = True)
Devilhunter

สวัสดี @Bakuriu มีวิธีใดที่จะได้จำนวน cpu cores ที่ถูกใช้โดยกระบวนการเฉพาะโดยใช้ psutil หรือไม่?
saichand

@Devilhunter บน Windows บน Intel i7-8700 ของฉันpsutil.cpu_count()ให้ 12 (เป็น 6-core CPU พร้อม hyperthreading) นี่เป็นเพราะอาร์กิวเมนต์เริ่มต้นของlogicalเป็น True ดังนั้นคุณต้องเขียนอย่างชัดเจนpsutil.cpu_count(logical = False)เพื่อรับจำนวน Cores ทางกายภาพ
OscarVanL

52

ในหลาม 3.4+: os.cpu_count ()

multiprocessing.cpu_count()ถูกนำมาใช้ในแง่ของฟังก์ชั่นนี้ แต่เพิ่มNotImplementedErrorว่าos.cpu_count()ผลตอบแทนNone("ไม่สามารถกำหนดจำนวนของ CPU")


4
cpu_countดูเพิ่มเติมเอกสารของ len(os.sched_getaffinity(0))อาจจะดีกว่าขึ้นอยู่กับวัตถุประสงค์
อัลเบิร์

1
@ อัลเบิร์ตใช่จำนวนของ CPU ในระบบ ( os.cpu_count()- เมื่อ OP ถาม) อาจแตกต่างจากจำนวนของ CPU ที่ใช้งานได้สำหรับกระบวนการปัจจุบัน ( os.sched_getaffinity(0))
jfs

ฉันรู้ว่า. ฉันแค่ต้องการเพิ่มสิ่งนั้นสำหรับผู้อ่านคนอื่น ๆ ที่อาจพลาดความแตกต่างนี้เพื่อให้ได้ภาพที่สมบูรณ์ยิ่งขึ้นจากพวกเขา
อัลเบิร์

1
เพิ่มเติม: os.sched_getaffinity(0)คือไม่ได้มีอยู่ใน BSD ดังนั้นการใช้os.cpu_count()จะต้อง (ไม่ห้องสมุดภายนอกอื่น ๆ ที่มี)
Cometsong

1
ควรสังเกตว่า os.sched_getaffinity ดูเหมือนจะไม่สามารถใช้ได้กับ Windows
manu3d

47

len(os.sched_getaffinity(0)) คือสิ่งที่คุณต้องการ

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

os.sched_getaffinity(0)(เพิ่มใน Python 3) ส่งคืนชุดของ CPU ที่พร้อมใช้งานเนื่องจากการsched_setaffinityเรียกระบบ Linuxซึ่ง จำกัด CPU ที่กระบวนการและลูกสามารถทำงานได้

0หมายถึงการรับค่าสำหรับกระบวนการปัจจุบัน ฟังก์ชั่นส่งกลับของซีพียูได้รับอนุญาตจึงจำเป็นที่จะต้องset()len()

multiprocessing.cpu_count() ในทางกลับกันเพียงแค่ส่งคืนจำนวน CPU ทางกายภาพทั้งหมด

ความแตกต่างเป็นสิ่งสำคัญอย่างยิ่งเพราะระบบการจัดการคลัสเตอร์บางอย่างเช่นแพลตฟอร์ม LSFการใช้งาน CPU sched_getaffinityงานกับขีด

ดังนั้นหากคุณใช้multiprocessing.cpu_count()สคริปต์ของคุณอาจลองใช้วิธีการแกนมากกว่าที่มีอยู่ซึ่งอาจนำไปสู่การโอเวอร์โหลดและหมดเวลา

เราสามารถเห็นความแตกต่างอย่างชัดเจนโดยการ จำกัด ความสัมพันธ์กับtasksetยูทิลิตี้

ตัวอย่างเช่นถ้าฉัน จำกัด Python เพียง 1 หลัก (core 0) ในระบบ 16 core ของฉัน:

taskset -c 0 ./main.py

ด้วยสคริปต์ทดสอบ:

main.py

#!/usr/bin/env python3

import multiprocessing
import os

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

ดังนั้นผลลัพธ์คือ:

16
1

nproc อย่างไรก็ตามจะเคารพความสัมพันธ์ตามค่าเริ่มต้นและ:

taskset -c 0 nproc

เอาท์พุท:

1

และman nprocทำให้ค่อนข้างชัดเจน:

พิมพ์จำนวนหน่วยการประมวลผลที่มีอยู่

nprocมี--allแฟล็กสำหรับกรณีทั่วไปที่น้อยกว่าที่คุณต้องการรับจำนวนฟิสิคัล CPU:

taskset -c 0 nproc --all

ข้อเสียเพียงอย่างเดียวของวิธีนี้คือสิ่งนี้ดูเหมือนว่าจะเป็น UNIX เท่านั้น ฉันคิดว่า Windows ต้องมี affinity API ที่คล้ายกันSetProcessAffinityMaskดังนั้นฉันจึงสงสัยว่าทำไมมันจึงไม่ได้รับการจัดวาง แต่ฉันไม่รู้อะไรเกี่ยวกับ Windows

ทดสอบใน Ubuntu 16.04, Python 3.5.2


3
ใช้งานได้กับ Unix เท่านั้น
Christopher Barber

@ChristopherBarber ขอบคุณสำหรับข้อมูลเพิ่มไปยังคำตอบ
Ciro Santilli 法轮功冠状病六四事件法轮功

33

แพลตฟอร์มอิสระ:

psutil.cpu_count (ตรรกะ = false)

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


4
อะไรคือความแตกต่างระหว่าง CPU แบบโลจิคัลและไม่ใช่แบบลอจิคัล ในแล็ปท็อปของฉัน: psutil.cpu_count(logical=False) #4 psutil.cpu_count(logical=True) #8และmultiprocessing.cpu_count() #8
user305883

1
@ user305883 สมมติว่าคุณมีซีพียู x86 คุณมีไฮเปอร์เธรดในเครื่องนี้นั่นคือแต่ละฟิสิคัลคอร์สอดคล้องกับไฮเปอร์เธรดสองอัน ('ตรรกะ' คอร์) การทำไฮเปอร์เธรดอนุญาตให้ใช้ฟิสิคัลคอร์เพื่อดำเนินการคำสั่งจากเธรด B เมื่อบางส่วนไม่ได้ใช้งานสำหรับเธรด A (เช่นรอข้อมูลที่ถูกดึงมาจากแคชหรือหน่วยความจำ) ขึ้นอยู่กับรหัสของคุณหนึ่งสามารถรับหนึ่งหรือสองสามสิบเปอร์เซ็นต์ของการใช้งานแกนเพิ่มเติม แต่มันต่ำกว่าประสิทธิภาพของแกนทางกายภาพจริง
Andre Holzner

23

สิ่งเหล่านี้จะช่วยให้คุณนับ CPU ที่มีเธรดมากเกินไป

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

สิ่งเหล่านี้จะให้คุณนับ CPU ของเครื่องเสมือน

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

จะทำงานก็ต่อเมื่อคุณทำงานบน VMs เท่านั้น


ไม่ได้จริงๆ ตามที่ระบุไว้os.cpu_count()และmultiprocessing.cpu_count()จะส่งคืนจำนวน CPU ที่มีเธรดมากไม่ใช่จำนวนจริงของ CPU
Christopher Barber

2
ใช่. ฉันพูดใหม่ โดยทั่วไปแล้วคือ # ของแกน x 2 สิ่งที่ฉันหมายถึงคือถ้าคุณอยู่บนเครื่องเสมือนที่แกะสลัก 8 คอร์ แต่เครื่องโฮสต์ของคุณคือ 20 แกนทางกายภาพชุดคำสั่งแรกให้คุณ 20 คำสั่งชุดที่สองให้คุณ 8.
yangliu2

21

multiprocessing.cpu_count()จะกลับมาจำนวนซีพียูตรรกะดังนั้นหากคุณมี CPU Quad-core กับ hyperthreading 8ก็จะกลับ หากคุณต้องการจำนวนฟิสิคัล CPU ให้ใช้การเชื่อมหลามเพื่อ hwloc:

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

hwloc ถูกออกแบบมาให้พกพาได้ทั้งในระบบปฏิบัติการและสถาปัตยกรรม


ในกรณีนี้ฉันต้องการจำนวนของ CPU แบบลอจิคัล (เช่นจำนวนเธรดที่ฉันควรเริ่มถ้าโปรแกรมนี้ปรับขนาดได้ดีจริง ๆ ) แต่คำตอบอาจมีประโยชน์อย่างไรก็ตาม
Phihag

7
หรือpsutil.cpu_count(logical=False)
TimZaman

8

ไม่สามารถหาวิธีเพิ่มรหัสหรือตอบกลับข้อความได้ แต่นี่คือการสนับสนุนสำหรับ jython ที่คุณสามารถแก้ไขได้ก่อนที่คุณจะยอมแพ้:

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

7

สิ่งนี้อาจใช้ได้กับพวกเราที่ใช้ระบบปฏิบัติการ / ระบบที่แตกต่างกัน แต่ต้องการได้รับประโยชน์สูงสุดจากโลกทั้งหมด:

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

5

คุณสามารถใช้ "joblib" เพื่อจุดประสงค์นี้

import joblib
print joblib.cpu_count()

วิธีนี้จะให้จำนวน cpus ในระบบ ต้องติดตั้ง joblib ข้อมูลเพิ่มเติมเกี่ยวกับ joblib สามารถดูได้ที่นี่ https://pythonhosted.org/joblib/parallel.html

หรือคุณสามารถใช้แพคเกจ numexpr ของ python มันมีฟังก์ชั่นง่าย ๆ มากมายที่เป็นประโยชน์สำหรับการรับข้อมูลเกี่ยวกับ cpu ระบบ

import numexpr as ne
print ne.detect_number_of_cores()

joblib ใช้โมดูลมัลติโพรเซสเซอร์ขั้นพื้นฐาน อาจเป็นการดีที่สุดที่จะโทรเข้าสู่การประมวลผลหลายทางโดยตรงสำหรับสิ่งนี้
ogrisel

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.