如何使用python找出CPU的数量

我想知道使用Python的本地机器上的CPU数量。当使用最佳缩放仅限用户空间的程序调用时,结果应该是user/real作为time(1)的输出。

505065 次浏览

如果你对当前进程的处理器数量可用感兴趣,你必须首先检查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')

如果你有版本>=2.6的python,你可以简单地使用

import multiprocessing


multiprocessing.cpu_count()

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

无法弄清楚如何添加到代码或回复消息,但这里有对jython的支持,您可以在放弃之前加入:

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

另一种选择是使用psutil库,它在这些情况下总是很有用:

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

这应该适用于psutil(Unix和Windows)支持的任何平台。

请注意,在某些情况下,multiprocessing.cpu_count可能会引发NotImplementedError,而psutil将能够获得CPU的数量。这仅仅是因为psutil首先尝试使用multiprocessing使用的相同技术,如果这些技术失败,它还会使用其他技术。

multiprocessing.cpu_count()将返回逻辑CPU的数量,所以如果你有一个带有超线程的四核CPU,它将返回8。如果你想要物理CPU的数量,请使用python绑定到hwloc:

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

HWLOC被设计为跨操作系统和架构可移植。

如果您没有Python 2.6,还有另一个选择:

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

在Python 3.4+中:os.cpu_count()

multiprocessing.cpu_count()是根据此函数实现的,但如果os.cpu_count()返回None(“无法确定CPU数量”),则会引发NotImplementedError

您也可以为此目的使用“joblib”。

import joblib
print joblib.cpu_count()

此方法将为您提供系统中的cpus数量。不过需要安装joblib。有关joblib的更多信息可以在此处找到https://pythonhosted.org/joblib/parallel.html

或者,您可以使用python的numexpr包。它有很多简单的功能,有助于获取有关系统cpu的信息。

import numexpr as ne
print ne.detect_number_of_cores()

如果你想知道物理内核(不是虚拟超线程内核)的数量,这里有一个独立于平台的解决方案:

psutil.cpu_count(logical=False)

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

请注意,logical的默认值是True,因此如果您确实想要包含超线程内核,您可以使用:

psutil.cpu_count()

这将给出与os.cpu_count()multiprocessing.cpu_count()相同的数字,两者都没有logical关键字参数。

这些为您提供超线程CPU计数

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

这些为您提供虚拟机CPU计数

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

只有在VM上工作时才重要。

len(os.sched_getaffinity(0))是你通常想要的

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

os.sched_getaffinity(0)(在Python 3中添加)返回考虑到sched_setaffinityLinux系统调用的可用CPU集,它限制了进程及其子进程可以在哪些CPU上运行。

0表示获取当前进程的值。该函数返回允许CPU的set(),因此需要len()

另一方面,multiprocessing.cpu_count()os.cpu_count()仅返回物理CPU的总数。

这种差异尤其重要,因为某些集群管理系统(例如平台LSF)使用sched_getaffinity限制作业CPU使用率。

因此,如果您使用multiprocessing.cpu_count(),您的脚本可能会尝试使用比可用内核更多的内核,这可能会导致过载和超时。

我们可以通过限制taskset实用程序的关联性来具体看到差异,它允许我们控制进程的关联性。

最小taskset示例

例如,如果我将Python限制为16个核心系统中的1个核心(核心0):

taskset -c 0 ./main.py

使用测试脚本:

main.py

#!/usr/bin/env python3


import multiprocessing
import os


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

则输出为:

16
16
1

vsnproc

nproc默认尊重亲和力,并且:

taskset -c 0 nproc

产出:

1

man nproc非常明确地说明了这一点:

打印可用的处理单元数量

因此,默认情况下,len(os.sched_getaffinity(0))的行为类似于nproc

nproc--all标志,用于在不考虑任务集的情况下获取物理CPU计数的不太常见的情况:

taskset -c 0 nproc --all

os.cpu_count留档

os.cpu_count的留档也简要提到了这个https://docs.python.org/3.8/library/os.html#os.cpu_count

这个数字不等于当前进程可以使用的CPU数量。可用CPU的数量可以通过len(os.sched_getaffinity(0))获得

同样的评论也复制在multiprocessing.cpu_counthttps://docs.python.org/3/library/multiprocessing.html#multiprocessing.cpu_count的留档上

Lib/multiprocessing/context.py下的3.8源代码中,我们还看到multiprocessing.cpu_count只是转发到os.cpu_count,除了multiprocessing抛出异常而不是在os.cpu_count失败时返回无:

    def cpu_count(self):
'''Returns the number of CPUs in the system'''
num = os.cpu_count()
if num is None:
raise NotImplementedError('cannot determine number of cpus')
else:
return num

3.8可用性:具有本机sched_getaffinity功能的系统

这个os.sched_getaffinity的唯一缺点是它似乎只是Python 3.8的UNIX。

cpython 3.8似乎只是尝试在配置时使用sched_setaffinity函数调用编译一个小型C hello world,如果不存在HAVE_SCHED_SETAFFINITY则未设置,该函数可能会丢失:

psutil.Process().cpu_affinity():带有Windows端口的第三方版本

第三方psutilpip install psutil)已在https://stackoverflow.com/a/14840102/895245中提及,但未在cpu_affinity函数中提及:https://psutil.readthedocs.io/en/latest/#psutil.Process.cpu_affinity

用法:

import psutil
print(len(psutil.Process().cpu_affinity()))

此函数与Linux上的标准库os.sched_getaffinity相同,但他们也通过调用GetProcessAffinityMask Windows API函数为Windows实现了它:

所以换句话说:那些Windows用户必须停止懒惰并向上游stdlib发送补丁:-)

在Ubuntu 16.04、Python 3.5.2中测试。

这可能适用于我们这些使用不同操作系统/系统的人,但希望获得世界上最好的:

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

如果你正在使用火炬,你可以这样做:

import torch.multiprocessing as mp


mp.cpu_count()

torch中的mp库与主python库具有相同的接口,因此您也可以像评论者提到的那样执行此操作:

python -c "import multiprocessing; print(multiprocessing.cpu_count())"

希望这有帮助!;)有不止一个选择总是很好的。

对于3.4以上的python版本,您可以使用

import os
os.cpu_count()

如果您正在寻找Linux命令nproc的等效项。您有这个选项

len(os.sched_getaffinity(0))

如果您正在寻找打印系统中的内核数量。

试试这个:

import os
no_of_cores = os.cpu_count()
print(no_of_cores)

这应该有帮助。