【问题标题】:Multiprocessing Pool() method has no effect on performanceMultiprocessing Pool() 方法对性能没有影响
【发布时间】:2021-09-05 10:37:48
【问题描述】:

我在多处理器机器上使用 Python 3.9.2 进行 Linux/Debian 测试。我正在尝试了解多处理的工作原理。

我编写了两个执行两个指数函数的简单脚本,一个没有多重处理,另一个有。

这是没有多重处理的:

from timeit import default_timer as timer


def sqr(n):

    a = n ** n

    return a


def sqr_2(m):

    b = m ** m

    return b


def main():

    start = timer()
    
    print(f'sqr = {sqr(100000)}\nsqr_2= {sqr_2(200000)}')
    
    end = timer()


    print(f'time frame in which the operation is resolved: {end - start} seconds')


if __name__ == '__main__':
    main()

这是使用多处理的脚本:

from multiprocessing import Pool, cpu_count
from timeit import default_timer as timer


def sqr_1(n):

    return n ** n


def sqr_2(m):

    return m ** m


def main():

    cpu_cnt = cpu_count()
    pool = Pool(processes = cpu_cnt)     #In this case there are 12 processors

    start = timer()
    
    val_1 = (100000,)
    val_2 = (200000,)
    
    process_1 = pool.map_async(sqr_1, val_1)
    process_2 = pool.map_async(sqr_2, val_2)
    
    print(f'Results: {process_1.get(), process_2.get()}')

    end = timer()

    print(f'time frame in which the operation is resolved: {end - start} seconds')


if __name__ == '__main__':
    main()

问题在于第二个脚本的进程在没有任何错误的情况下完成,在相同的时间内(大约 14 秒)执行了与第一个脚本相同的任务。因此,第二个脚本中的多处理不起作用。我提前感谢任何想指出这是错误的人!

【问题讨论】:

  • 您将需要在每个流程中做比单个数学运算更多的工作,以证明启动流程所需的时间是合理的。请注意,您的时间包括将数学结果转换为十进制,这一切都发生在主过程中(并且可能比数学本身花费更长的时间)。
  • 你误会了。当您使用多处理池时,库必须启动一个新进程,并使用一个新的解释器副本,它必须从头开始重新初始化。然后它必须重新加载你的脚本,然后它才能运行你的函数。现在,您让每个进程运行一个幂运算符。启动和初始化新解释器的成本比你的一个函数的成本高出数千倍。如果你想看到好处,你需要在你的 sqr 函数中做更多的事情。
  • 通过 2 次调用 sqr,串行/并行脚本在我的机器上都在 0.3 秒内运行(跳过结果的实际输出,这是最耗时的部分)。增加最多 6 个调用,分割变为 4.3 秒与 2.1 秒。并行化总是有一些开销,但是当你实际上可以并行的工作越多时,开销就变得越小。
  • 非常有趣,谢谢..事实上,如果我不打印数字结果(没用的东西,但我想确保它做了这个操作)池的结果只有在0.14 秒
  • ..实际上没有打印数字结果,如果我将两个操作数都增加一个零,我会在 9 秒内使用没有池的脚本和 6 秒内获得其他脚本的操作结果

标签: python multiprocessing pool


【解决方案1】:

考虑以下脚本。它允许您在运行时选择调用函数的次数,以及是串行还是并行执行。它也只是计算值;它不会尝试将字符串表示形式写入标准输出(因为将n**n 的结果转换为字符串对于大型n 而言比实际计算要耗时得多)。

from multiprocessing import Pool, cpu_count
from timeit import default_timer as timer
import sys


def f(n):
    return n ** n


def main():
    cpu_cnt = cpu_count()
    n = int(sys.argv[2])
    start = timer()
    if sys.argv[1] == "s":
        s = [f(100000) for _ in range(n)]
    else:
        pool = Pool(processes = cpu_cnt)
        s = [pool.map_async(f, (100000,)) for _ in range(n)]
        results = [x.get() for x in s]
    end = timer()
    print(f'time frame in which the operation is resolved: {end - start} seconds')


if __name__ == '__main__':
    main()

以下是我的 4 核机器上 2、6、12、24、48、96 和 192 次函数调用的结果:

% for n in 2 6 12 24 48 96 192; do print $n; for x in s p; do python3 tmp.py $x $n; done; done
2
time frame in which the operation is resolved: 0.146144435 seconds
time frame in which the operation is resolved: 0.178840965 seconds
6
time frame in which the operation is resolved: 0.423103791 seconds
time frame in which the operation is resolved: 0.24940852500000002 seconds
12
time frame in which the operation is resolved: 0.848754817 seconds
time frame in which the operation is resolved: 0.340022419 seconds
24
time frame in which the operation is resolved: 1.691312521 seconds
time frame in which the operation is resolved: 0.571664972 seconds
48
time frame in which the operation is resolved: 3.415401498 seconds
time frame in which the operation is resolved: 1.029526396 seconds
96
time frame in which the operation is resolved: 6.76773454 seconds
time frame in which the operation is resolved: 2.016387216 seconds
192
time frame in which the operation is resolved: 13.529949021999998 seconds
time frame in which the operation is resolved: 3.770171452 seconds

只有 2 个并行进程,由于并行化本身的开销,没有加速。 (事实上​​,有一个减速。)一旦你开始运行更多的进程,加速就会增加,但对于 n 内核,你永远不会看到 n 的加速。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-04
    • 2011-11-12
    • 2014-01-05
    • 1970-01-01
    • 2019-09-04
    相关资源
    最近更新 更多