12

我正在尝试在 Python (Windows Server 2012) 中实现多处理,并且无法达到我期望的性能改进程度。特别是,对于一组几乎完全独立的任务,我希望通过额外的核心实现线性改进


我知道——尤其是在 Windows 上——打开新进程会产生开销[1],并且底层代码的许多怪癖可能会阻碍一个干净的趋势。但理论上,对于完全并行化的任务[2] ,趋势最终仍应接近线性;或者如果我正在处理部分串行任务[3] ,则可能是逻辑的。

N_cores=36但是,当我在质数检查测试函数(下面的代码)上运行 multiprocessing.Pool 时,在我进入预期性能之前,我得到了一个几乎完美的平方根关系(我的服务器上的物理内核数)额外的逻辑核心。


是我的性能测试结果图:( 标准化性能”是[具有1 个CPU 核心的运行时间]除以[具有N个 CPU 核心的运行时间])。在此处输入图像描述


多处理导致收益急剧减少是否正常?还是我的实施遗漏了什么?


import numpy as np
from multiprocessing import Pool, cpu_count, Manager
import math as m
from functools import partial
from time import time

def check_prime(num):

    #Assert positive integer value
    if num!=m.floor(num) or num<1:
        print("Input must be a positive integer")
        return None

    #Check divisibility for all possible factors
    prime = True
    for i in range(2,num):
        if num%i==0: prime=False
    return prime

def cp_worker(num, L):
    prime = check_prime(num)
    L.append((num, prime))


def mp_primes(omag, mp=cpu_count()):
    with Manager() as manager:
        np.random.seed(0)
        numlist = np.random.randint(10**omag, 10**(omag+1), 100)

        L = manager.list()
        cp_worker_ptl = partial(cp_worker, L=L)

        try:
            pool = Pool(processes=mp)   
            list(pool.imap(cp_worker_ptl, numlist))
        except Exception as e:
            print(e)
        finally:
            pool.close() # no more tasks
            pool.join()

        return L


if __name__ == '__main__':
    rt = []
    for i in range(cpu_count()):
        t0 = time()
        mp_result = mp_primes(6, mp=i+1)
        t1 = time()
        rt.append(t1-t0)
        print("Using %i core(s), run time is %.2fs" % (i+1, rt[-1]))

注意:我知道对于这个任务,实现多线程可能会更有效,但是由于 GIL,这个简化模拟的实际脚本与 Python 多线程不兼容。

4

1 回答 1

9

@KellanM值得[+1] 用于定量性能监控

我的实施是否遗漏了什么?

是的,您从流程管理的所有附加成本中抽象出来。

虽然您已经表达了对“增加内核的线性改进”的期望,但这在实践中几乎不会出现,原因有几个(即使是共产主义的炒作也未能免费提供任何东西)。

Gene AMDAHL 制定了收益递减的初始法则。 一个更新的、重新制定的版本也考虑了流程管理 {setup|terminate} 的影响 -附加开销成本,并试图应对处理的原子性(给定大型工作包有效负载不容易重新在最常见的编程系统中定位/重新分布在可用的免费 CPU 内核池上(除了一些确实特定的微调度艺术,如 Semantic Design 的 PARLANSE 或 LLNL 的 SISAL 过去展示的那样丰富多彩)。在此处输入图像描述


最好的下一步?

如果确实对这个领域感兴趣,人们可能总是通过实验测量和比较流程管理的实际成本(加上数据流成本,加上内存分配成本,......直到流程终止和结果重新组装过程),以便在数量上公平地记录和评估使用更多 CPU 内核的附加成本/收益比(这将python在第一个有用的操作将在第一个生成和设置过程中执行)。

性能不佳(对于下面的前一种情况)
如果不是灾难性影响(来自下面的后一种情况),
无论是设计不当的资源映射策略,无论是来自CPU核心池的“
预订不足”资源还是此处讨论了超额预订”-来自RAM池的资源-空间


上述重新制定的阿姆达尔定律的链接将帮助您评估收益递减点,而不是支付比以往任何时候都多的钱。

Hoefinger 和 Haunschmid 的实验可以作为一个很好的实际证据,越来越多的处理节点(无论是本地 O/S 管理的 CPU 核心,还是 NUMA 分布式架构节点)将如何开始降低所产生的性能,
其中一个点收益递减(在开销不可知论的阿姆达尔定律中得到证明)
实际上将开始成为一个点,在此之后你付出的比得到的多。

在此处输入图像描述 祝你在这个有趣的领域好运! 在此处输入图像描述


最后但并非最不重要的,

NUMA / non-locality 问题在讨论 HPC 级调整(缓存内 / RAM 内计算策略)的扩展讨论中得到了他们的声音,并且可能 - 作为副作用 - 帮助检测缺陷(如@报告的那样)上面的eryksun)。一旦在这样的 NUMA 资源拓扑上安排“公正”任务执行,人们可能会随意使用lstopo工具查看自己的平台实际 NUMA 拓扑,以查看操作系统尝试使用的抽象:[CONCURRENT]

在此处输入图像描述

于 2018-05-07T20:16:38.147 回答