在多处理模块中使用100%的核心

Ggg*_*ggg 44 python multiprocessing python-3.x

我有两段代码,我用它来学习Python 3.1中的多处理.我的目标是使用所有可用处理器的100%.但是,此处的代码片段仅在所有处理器上达到30% - 50%.

无论如何'强制'python使用全部100%?操作系统(Windows 7,64位)是否限制了Python对处理器的访问?虽然下面的代码片段正在运行,但我打开任务管理器并观察处理器的峰值,但从未达到并维持100%.除此之外,我还可以看到在此过程中创建和销毁了多个python.exe进程.这些过程如何与处理器相关?例如,如果我生成4个进程,则每个进程都不使用它自己的核心.相反,使用的流程是什么?他们共享所有核心吗?如果是这样,操作系统是否迫使进程共享内核?

代码段1

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()
Run Code Online (Sandbox Code Playgroud)

代码段2

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()
Run Code Online (Sandbox Code Playgroud)

S.L*_*ott 41

要使用100%的所有核心,请不要创建和销毁新进程.

为每个核心创建一些进程并将它们与管道链接.

在操作系统级别,所有流水线进程同时运行.

您写的越少(您委托给操作系统的次数越多),您使用尽可能多的资源的可能性就越大.

python p1.py | python p2.py | python p3.py | python p4.py ...
Run Code Online (Sandbox Code Playgroud)

将最大限度地利用您的CPU.

  • 你上面所拥有的是Python的"多处理"模块将为你做的事情. (13认同)
  • 一些启动一次并通过它们移动数据的进程通常比尝试启动大量进程更有效.此外,操作系统调度非常非常好,因为它是直接在OS API上构建的,没有包装器或帮助器. (2认同)

Ioa*_*dis 13

您可以使用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()
Run Code Online (Sandbox Code Playgroud)

注意:如评论所述,psutil.Process.cpu_affinitymacOS上不可用.

  • `proc.cpu_affinity` 仅适用于 `Windows、Linux 和 FreeBSD`。 (2认同)

std*_*err 6

关于代码片段1:您的测试机器上有多少个核心/处理器?如果您只有2个CPU核心,那么运行其中50个进程对您没有任何帮助.实际上,您正在强制操作系统花费更多时间进行上下文切换,以便在CPU上下移动进程,而不是实际工作.

尝试将生成的进程数减少到核心数.所以"对于范围内的我(50):"应该变得像:

import os;
# assuming you're on windows:
for i in range(int(os.environ["NUMBER_OF_PROCESSORS"])):
    ...
Run Code Online (Sandbox Code Playgroud)

关于代码片段2:您正在使用multiprocessing.Lock,它一次只能由一个进程保存,因此您完全限制了此版本程序中的所有并行性.你已经序列化了一些东西,以便进程1到50开始,一个随机进程(比如进程7)获取锁.进程1-6和8-50都在线上:

l.acquire()
Run Code Online (Sandbox Code Playgroud)

当他们坐在那里他们只是在等待释放锁.根据Lock原语的实现,他们可能没有使用任何CPU,他们只是坐在那里使用系统资源,如RAM,但没有与CPU有用的工作.进程7计数并打印到1000然后释放锁.然后操作系统可以随机安排其余49个进程中的一个进行运行.无论哪一个先醒来,它都会获得锁定并继续运行,而其余48个等待锁定.这将继续整个计划.

基本上,代码片段2是使并发变得困难的一个例子.您必须通过许多进程或线程来管理对某些共享资源的访问.在这种特殊情况下,这些过程实际上没有理由需要相互等待.

因此,在这两者中,Snippet 1更接近于更有效地利用CPU.我认为适当调整进程数以匹配核心数将产生大大改善的结果.

  • 使用环境变量`from multiprocessing import cpu_count的替代方法; for x in xrange(cpu_count()):...` (6认同)

THN*_*THN 6

纯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))
Run Code Online (Sandbox Code Playgroud)

用法:在寒冷的天气进行预热(但可以随时将循环更改为没有意义的东西。)

警告:要退出,请不要拔插头或按住电源按钮,而请按Ctrl-C。