python 多处理:没有递减 returns?
python multiprocessing: no diminishing returns?
假设我想并行化一些密集计算(不受 I/O 约束)。
当然,我不想 运行 比可用处理器更多的进程,否则我会开始为上下文切换(和缓存未命中)付费。
在心理上,我希望随着我在 multiprocessing.Pool(n)
中增加 n
,总时间会像这样:
- 负斜率,因为任务利用了并行化
- 正斜率,因为上下文切换开始让我付出代价
- 高原
但实际上,我得到的是:
#!/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
操作系统:Ubuntu14.04
在 n>4 之后,我看到任务管理器在各个进程之间轮换,正如预期的那样,因为进程比处理器多。然而,相对于 n=4(我的处理器数量)没有惩罚。
事实上,即使当 n<4 时,我也看到调度程序在我的处理器中疯狂地轮换进程,而不是将每个进程分配给它自己的处理器并避免上下文切换。
我在使用 gnome-system-monitor 时看到了这种行为:(如果有人有不同的经历,请告诉我。)
任何解释为什么我启动多少个进程似乎无关紧要?还是我的代码有问题?
我的猜测:似乎进程不受处理器限制(即使只有两个进程处于活动状态,它们也会不断切换 CPU),所以我无论如何都要为上下文切换付费。
参考文献:
编辑:更新了具有更高常量的图形和代码。
In fact, even when n<4, I see the scheduler frenetically rotating the
processes through my processors, instead of assigning each process to
its own processor and avoid context switching.
默认情况下,进程不是 processor-bounded,主要原因之一是避免处理器受热不均匀,这会导致机械应力并缩短其使用寿命。
有一些方法可以在单核上强制执行 运行 进程(参见 psutil
模块),这具有更好地使用高速缓存和避免上下文切换等优点,但在大多数情况下情况下(如果不是全部的话),你在性能方面不会有太大的不同。
所以现在如果生成的进程多于您的核心数量,它们将仅充当线程并在它们之间切换以优化执行。处理器性能只会(非常)轻微降低,因为您已经用少于 4 个进程切换上下文。
回答我自己的问题:
首先,我的post似乎有误。正在使用的 CPU 被疯狂地改变似乎不是真的。如果我启动两个 CPU 密集型进程,它们会不断更换核心,但仅限于两个核心之间。我的计算机有 4 个内核,每个内核有 2 "soft" 个内核(用于超线程)。我想发生的事情是它在这 2 "soft" 个核心之间发生变化。不是 Linux 这样做,而是 CPU-板。
话虽这么说,但我仍然很惊讶上下文切换并没有比现在更痛苦。
编辑: this blog.
有一个很好的讨论,经验工作比我好
假设我想并行化一些密集计算(不受 I/O 约束)。
当然,我不想 运行 比可用处理器更多的进程,否则我会开始为上下文切换(和缓存未命中)付费。
在心理上,我希望随着我在 multiprocessing.Pool(n)
中增加 n
,总时间会像这样:
- 负斜率,因为任务利用了并行化
- 正斜率,因为上下文切换开始让我付出代价
- 高原
但实际上,我得到的是:
#!/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
操作系统:Ubuntu14.04
在 n>4 之后,我看到任务管理器在各个进程之间轮换,正如预期的那样,因为进程比处理器多。然而,相对于 n=4(我的处理器数量)没有惩罚。
事实上,即使当 n<4 时,我也看到调度程序在我的处理器中疯狂地轮换进程,而不是将每个进程分配给它自己的处理器并避免上下文切换。
我在使用 gnome-system-monitor 时看到了这种行为:(如果有人有不同的经历,请告诉我。)
任何解释为什么我启动多少个进程似乎无关紧要?还是我的代码有问题?
我的猜测:似乎进程不受处理器限制(即使只有两个进程处于活动状态,它们也会不断切换 CPU),所以我无论如何都要为上下文切换付费。
参考文献:
编辑:更新了具有更高常量的图形和代码。
In fact, even when n<4, I see the scheduler frenetically rotating the processes through my processors, instead of assigning each process to its own processor and avoid context switching.
默认情况下,进程不是 processor-bounded,主要原因之一是避免处理器受热不均匀,这会导致机械应力并缩短其使用寿命。
有一些方法可以在单核上强制执行 运行 进程(参见 psutil
模块),这具有更好地使用高速缓存和避免上下文切换等优点,但在大多数情况下情况下(如果不是全部的话),你在性能方面不会有太大的不同。
所以现在如果生成的进程多于您的核心数量,它们将仅充当线程并在它们之间切换以优化执行。处理器性能只会(非常)轻微降低,因为您已经用少于 4 个进程切换上下文。
回答我自己的问题:
首先,我的post似乎有误。正在使用的 CPU 被疯狂地改变似乎不是真的。如果我启动两个 CPU 密集型进程,它们会不断更换核心,但仅限于两个核心之间。我的计算机有 4 个内核,每个内核有 2 "soft" 个内核(用于超线程)。我想发生的事情是它在这 2 "soft" 个核心之间发生变化。不是 Linux 这样做,而是 CPU-板。
话虽这么说,但我仍然很惊讶上下文切换并没有比现在更痛苦。
编辑: this blog.
有一个很好的讨论,经验工作比我好