【问题标题】:python multiprocessing: no diminishing returns?python多处理:没有收益递减?
【发布时间】:2016-01-23 15:10:30
【问题描述】:

假设我想并行化一些密集计算(不受 I/O 限制)。

当然,我不想运行比可用处理器更多的进程,否则我会开始为上下文切换(和缓存未命中)付费。

在心理上,我预计随着 nmultiprocessing.Pool(n) 中的增加,总时间会像这样:

  1. 任务利用并行化的负斜率
  2. 正斜率,因为上下文切换开始让我付出代价
  3. 高原

但实际上,我得到了这个:

#!/usr/bin/env python

from math import factorial


def pi(n):
    t = 0
    pi = 0
    deno = 0
    k = 0
    for k in range(n):
        t = ((-1)**k)*(factorial(6*k))*(13591409+545140134*k)
        deno = factorial(3*k)*(factorial(k)**3)*(640320**(3*k))
        pi += t/deno
    pi = pi * 12/(640320**(1.5))
    pi = 1/pi
    return pi

import multiprocessing
import time
maxx = 20
tasks = 60
task_complexity = 500
x = range(1, maxx+1)
y = [0]*maxx

for i in x:
    p = multiprocessing.Pool(i)
    tic = time.time()
    p.map(pi, [task_complexity]*tasks)
    toc = time.time()
    y[i-1] = toc-tic
    print '%2d %ds' % (i, y[i-1])

import matplotlib.pyplot as plot
plot.plot(x, y)
plot.xlabel('Number of threads')
plot.xlim(1, maxx)
plot.xticks(x)
plot.ylabel('Time in seconds')
plot.show()

我的机器:i3-3217U CPU @ 1.80GHz × 4

操作系统:Ubuntu 14.04

在 n>​​4 之后,我看到任务管理器在各个进程中循环,正如预期的那样,因为进程多于处理器。然而,相对于 n=4(我的处理器数量)没有任何惩罚。

事实上,即使在 n

我在使用 gnome-system-monitor 时看到了这种行为:(如果有人有不同的体验,请告诉我。)

任何解释为什么我触发多少进程似乎并不重要?还是我的代码有问题?

我的猜测:似乎进程不受处理器限制(即使只有两个进程处于活动状态,它们也会不断切换 CPU),因此无论如何我都要为上下文切换付费。

参考资料:

编辑:用更高的常数更新了图形和代码。

【问题讨论】:

  • 出于兴趣:您有多少个处理器线程可用?
  • @poke,我忘了提。 :) 我同时添加了这些信息和其他信息。
  • 为了清楚起见:i3-3217U 有 2 个核心,每个核心有 2 个核心线程。您可能还应该测量累积的计算时间,以更好地了解上下文切换如何影响您的计算,here 我已经发布了您的脚本的修改版本(没有绘图的东西,因为我现在没有安装 matplotlib)。
  • @mata 我会尽快报告。无论如何,如果有人可以在其他机器和操作系统中尝试这个,那也很有趣。我将验证一个类似的答案。

标签: python multithreading multiprocess


【解决方案1】:

事实上,即使 n

默认情况下,进程不受处理器限制,主要原因之一是避免处理器受热不均,否则会导致机械应力并缩短其寿命。

有一些方法可以强制在单核上运行进程(查看psutil 模块),它具有更好地使用高速缓存和避免上下文切换等优点,但在大多数情况下(如果不是全部),你不要在性能方面产生太大影响。

所以现在,如果生成的进程数超过您的内核数,它们将充当线程并在它们之间切换以优化执行。处理器性能只会(非常)略微降低,因为您已经在少于 4 个进程的情况下切换上下文。

【讨论】:

  • 我喜欢你的加热解释,我认为这是故事的一部分,但我不太相信。他们可以通过每 30 分钟左右更换一次核心来避免加热,而不是每秒或更少。我被告知在 Windows 中不会发生这种持续的处理器切换。无论如何,如果没有人有任何其他解释,我将标记为正确。 ps:我已经添加了我用来查看此行为的工具的屏幕截图,以防有人可以证实它......
  • 感谢提及psutil;当我找到一些时间时,我会更改代码,看看我是否可以提高性能。为了将来参考,taskset(1) 命令看起来也很有趣。
  • 有多种算法(依赖于操作系统)在处理器上调度任务。我寻找比加热问题更好的答案,但我没有找到太多关于为什么单线程程序需要进程切换的问题。我发现一篇文章描述了使用上下文切换算法可能提高性能,但我不知道这是使用还是仅用于研究材料。
  • 但是我认为满载的核心发热非常非常快:如果您开始一项繁重的任务,您可以在几秒钟内听到风扇加速的声音。我认为等待 30 分钟太长了。
  • 我最近才开始处理繁重的工作。我一直在密切关注调度程序的行为,看来我是错误的。进程不断随机更换内核是不正确的。每个进程似乎只在两个核心之间发生变化。我的电脑有四个物理核心,每个核心都有两个“软”超线程核心。我认为改变内核的不是 Linux 调度程序,而是这种明显的内核变化是架构的产物。似乎不存在不必要的上下文切换。
【解决方案2】:

回答我自己的问题:

首先,我似乎在我的帖子中犯了一个错误。正在使用的 CPU 被疯狂地改变似乎不是真的。如果我启动两个 CPU 密集型进程,它们会不断更改内核,但仅在两个内核之间。我的电脑有 4 个核心,每个核心有 2 个“软”核心(用于超线程)。我想发生的事情是这两个“软”核心之间发生了变化。这样做的不是 Linux,而是 CPU 板。

话虽如此,我仍然很惊讶上下文切换并不比它更痛苦。

编辑:关于this blog,有一个很好的讨论,比我有更好的经验工作。

【讨论】:

    猜你喜欢
    • 2017-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-10
    • 2021-02-11
    • 1970-01-01
    • 1970-01-01
    • 2011-05-14
    相关资源
    最近更新 更多