[英]Using 100% of all cores with the multiprocessing module
我有两段代码用于学习 Python 3.1 中的多处理。 我的目标是使用 100% 的所有可用处理器。 但是,此处的代码片段在所有处理器上仅达到 30% - 50%。
无论如何要“强制”python 使用所有 100%? 操作系统(Windows 7、64 位)是否限制了 Python 对处理器的访问? 当下面的代码片段正在运行时,我打开任务管理器并观察处理器的峰值,但从未达到并保持 100%。 除此之外,我还可以看到在此过程中创建和销毁了多个 python.exe 进程。 这些过程与处理器有什么关系? 例如,如果我生成 4 个进程,则每个进程都没有使用它自己的核心。 相反,进程使用的是什么? 他们是否共享所有核心? 如果是这样,是否是操作系统强制进程共享内核?
import multiprocessing
def worker():
#worker function
print ('Worker')
x = 0
while x < 1000:
print(x)
x += 1
return
if __name__ == '__main__':
jobs = []
for i in range(50):
p = multiprocessing.Process(target=worker)
jobs.append(p)
p.start()
from multiprocessing import Process, Lock
def f(l, i):
l.acquire()
print('worker ', i)
x = 0
while x < 1000:
print(x)
x += 1
l.release()
if __name__ == '__main__':
lock = Lock()
for num in range(50):
Process(target=f, args=(lock, num)).start()
要 100% 使用所有内核,请不要创建和销毁新进程。
每个核心创建几个进程并将它们与管道链接。
在操作系统级别,所有流水线进程同时运行。
你写的越少(你委托给操作系统的越多),你就越有可能使用尽可能多的资源。
python p1.py | python p2.py | python p3.py | python p4.py ...
将最大限度地利用您的 CPU。
您可以使用psutil
将multiprocessing
产生的每个进程固定到特定 CPU:
import multiprocessing as mp
import psutil
def spawn():
procs = list()
n_cpus = psutil.cpu_count()
for cpu in range(n_cpus):
affinity = [cpu]
d = dict(affinity=affinity)
p = mp.Process(target=run_child, kwargs=d)
p.start()
procs.append(p)
for p in procs:
p.join()
print('joined')
def run_child(affinity):
proc = psutil.Process() # get self pid
print('PID: {pid}'.format(pid=proc.pid))
aff = proc.cpu_affinity()
print('Affinity before: {aff}'.format(aff=aff))
proc.cpu_affinity(affinity)
aff = proc.cpu_affinity()
print('Affinity after: {aff}'.format(aff=aff))
if __name__ == '__main__':
spawn()
注意:正如所评论的, psutil.Process.cpu_affinity
在 macOS 上不可用。
纯 Python 中的最小示例:
def f(x):
while 1:
# ---bonus: gradually use up RAM---
x += 10000 # linear growth; use exponential for faster ending: x *= 1.01
y = list(range(int(x)))
# ---------------------------------
pass # infinite loop, use up CPU
if __name__ == '__main__': # name guard to avoid recursive fork on Windows
import multiprocessing as mp
n = mp.cpu_count() * 32 # multiply guard against counting only active cores
with mp.Pool(n) as p:
p.map(f, range(n))
用法:在寒冷的一天热身(但可以随意将循环更改为不那么毫无意义的东西。)
警告:要退出,请不要拔插头或按住电源按钮,而是按 Ctrl-C。
关于代码片段 1:您的测试机器上有多少个内核/处理器? 如果您只有 2 个 CPU 内核,那么运行 50 个这样的进程对您没有任何好处。 事实上,与实际工作相比,您正在迫使操作系统花费更多的时间上下文切换来将进程移入和移出 CPU。
尝试将生成的进程数减少到内核数。 所以“for i in range(50):”应该变成这样:
import os;
# assuming you're on windows:
for i in range(int(os.environ["NUMBER_OF_PROCESSORS"])):
...
关于代码片段 2:您正在使用 multiprocessing.Lock,它一次只能由一个进程持有,因此您完全限制了此版本程序中的所有并行性。 您已将事物序列化,以便进程 1 到 50 启动,随机进程(例如进程 7)获取锁。 进程1-6、8-50都在排队:
l.acquire()
当他们坐在那里时,他们只是在等待锁被释放。 根据 Lock 原语的实现,他们可能不使用任何 CPU,他们只是坐在那里使用系统资源,如 RAM,但不使用 CPU 做任何有用的工作。 进程 7 计数并打印到 1000,然后释放锁。 然后操作系统可以自由地随机安排剩余的 49 个进程中的一个运行。 无论哪个先唤醒,接下来都会获取锁并运行,而其余 48 个则等待锁。 这将在整个程序中继续。
基本上,代码片段 2 是使并发变得困难的一个例子。 您必须管理许多进程或线程对某些共享资源的访问。 在这种特殊情况下,这些进程确实没有理由需要相互等待。
因此,在这两者中,代码段 1 更接近于更有效地利用 CPU。 我认为适当调整进程数以匹配内核数会产生很大的改进结果。
我建议使用Joblib库,它是一个很好的多处理库,用于许多 ML 应用程序、sklearn 等。
from joblib import Parallel, delayed
Parallel(n_jobs=-1, prefer="processes", verbose=6)(
delayed(function_name)(parameter1, parameter2, ...)
for parameter1, parameter2, ... in object
)
其中n_jobs
是并发作业的数量。 如果要使用运行代码的机器上的所有可用内核,请设置n=-1
。
有关此处参数的更多详细信息: https : //joblib.readthedocs.io/en/latest/generated/joblib.Parallel.html
在您的情况下,可能的实现是:
def worker(i):
print('worker ', i)
x = 0
while x < 1000:
print(x)
x += 1
Parallel(n_jobs=-1, prefer="processes", verbose=6)(
delayed(worker)(num)
for num in range(50)
)
回答您的问题:
无论如何要“强制”python 使用所有 100%?
不是我听说过
操作系统(Windows 7、64 位)是否限制了 Python 对处理器的访问?
是和否,是的:如果 python 占用 100%,Windows 将冻结。 不,您可以授予 python 管理员权限,这将导致锁定。
这些过程与处理器有什么关系?
他们没有,从技术上讲,在操作系统级别,那些 python“进程”是由操作系统处理程序在需要处理时处理的线程。
相反,进程使用的是什么? 他们是否共享所有核心? 如果是这样,是否是操作系统强制进程共享内核?
它们共享所有核心,除非您启动一个将亲缘性设置为某个核心(在多核系统中)的单个 python 实例,否则您的进程将被拆分为无核的处理。 所以是的,操作系统在默认情况下强制核心共享(或者 python 是技术上的)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.