为什么多处理的每个进程开销不断增加?
Why does per-process overhead constantly increase for multiprocessing?
我一直在计算一个 6 核 CPU,在 for 循环中有 12 个逻辑 CPUs,直到数次非常高的数字。
为了加快速度,我使用了多处理。我期待的是:
- 进程数 <= CPUs 的数量 = 时间相同
- 进程数 + 1 = CPUs = 时间加倍
我发现的是时间的持续增加。我很困惑。
密码是:
#!/usr/bin/python
from multiprocessing import Process, Queue
import random
from timeit import default_timer as timer
def rand_val():
num = []
for i in range(200000000):
num = random.random()
print('done')
def main():
for iii in range(15):
processes = [Process(target=rand_val) for _ in range(iii)]
start = timer()
for p in processes:
p.start()
for p in processes:
p.join()
end = timer()
print(f'elapsed time: {end - start}')
print('for ' + str(iii))
print('')
if __name__ == "__main__":
main()
print('done')
结果:
- 经过的时间:14.9477102 for 1
- 经过时间:15.4961154 for 2
- 经过时间:16.9633134 3
- 经过时间:18.723183399999996 4
- 经过时间:21.568377299999995 5
- 经过时间:24.126758499999994 for 6
- 经过时间:29.142095499999996 for 7
- 已用时间:33.175509300000016 为 8
。
.
.
- 经过的时间:44.629786800000005 for 11
- 经过的时间:46.22480710000002 for 12
- 经过的时间:50.44349420000003 for 13
- 已用时间:54.61919949999998 为 14
我不明白你想达到什么目的?
您正在做同样的工作,并且 运行 它 X 次,其中 X 是循环中 SMP 的数量。您应该接管工作并将其除以 X,然后将一个块发送到每个 SMP 单元。
无论如何,关于您所观察到的情况 - 您看到了生成和关闭单独进程所花费的时间。 Python 启动新流程的速度不快。
您的测试有误。
试想一下,一个农民用一台拖拉机耕种 10 公里^2 的农田需要 1 天。如果有两个农民在 20 公里 ^2 的农场上工作,为什么你期望两个农民使用两台拖拉机在两倍的农田上工作花费更少的时间?
你有6个CPU核心,你的村子有6台拖拉机,但是没有人有钱买私人拖拉机。随着村里工人(工序)的增加,拖拉机的数量却保持不变,大家不得不共享有限的拖拉机。
在理想世界中,两个农民使用两台拖拉机完成两倍的工作量与一个农民完成一份工作所花费的时间完全相同,但在真实的计算机中,机器甚至还有其他工作要做如果它看起来很闲。有任务切换,OS 内核必须 运行 并监控硬件设备,内存缓存需要在 CPU 个内核之间刷新和失效,你的浏览器需要 运行,村里的长老正在开会,讨论谁应该得到拖拉机,什么时候得到等等
随着工人数量的增加超过拖拉机的数量,农民不再只是独占拖拉机。相反,他们安排每三个小时左右让拖拉机经过一次。这意味着第七个农民不必等待两天就可以得到他们的拖拉机时间。然而,在农田之间转移拖拉机是有成本的,就像 CPU 在进程之间切换一样;任务切换太频繁,CPU 实际上没有工作,切换不频繁,你会资源匮乏,因为有些工作需要很长时间才能开始处理。
一个更明智的测试是保持耕地面积不变,只增加农民的数量。在您的代码中,这将对应于此更改:
def rand_val(num_workers):
num = []
for i in range(200000000 / num_workers):
num = random.random()
print('done')
def main():
for iii in range(15):
processes = [Process(target=lambda: rand_val(iii)) for _ in range(iii)]
...
你有两个错误的假设:
- 进程不是免费的。仅添加进程会增加程序的开销。
- 进程不拥有 CPUs。 CPU 交错执行多个进程。
第一点是为什么您会看到一些开销,即使进程少于 CPUs。请注意,您的系统通常有多个后台进程 运行ning,因此“少于 CPUs 的进程”这一点对于单个应用程序而言并不明确。
第二点是为什么当进程数超过CPU秒时,执行时间会逐渐增加。任何 OS 运行ning 主线 Python 都会 preemptive multitasking of processes;粗略地说,这意味着一个进程在完成之前不会阻塞 CPU,而是定期暂停以便其他进程可以 运行.
实际上,这意味着多个进程可以同时在一个 CPU 上 运行。由于 CPU 每次仍只能执行固定数量的工作,因此所有进程都需要更长的时间才能完成。
我一直在计算一个 6 核 CPU,在 for 循环中有 12 个逻辑 CPUs,直到数次非常高的数字。
为了加快速度,我使用了多处理。我期待的是:
- 进程数 <= CPUs 的数量 = 时间相同
- 进程数 + 1 = CPUs = 时间加倍
我发现的是时间的持续增加。我很困惑。
密码是:
#!/usr/bin/python
from multiprocessing import Process, Queue
import random
from timeit import default_timer as timer
def rand_val():
num = []
for i in range(200000000):
num = random.random()
print('done')
def main():
for iii in range(15):
processes = [Process(target=rand_val) for _ in range(iii)]
start = timer()
for p in processes:
p.start()
for p in processes:
p.join()
end = timer()
print(f'elapsed time: {end - start}')
print('for ' + str(iii))
print('')
if __name__ == "__main__":
main()
print('done')
结果:
- 经过的时间:14.9477102 for 1
- 经过时间:15.4961154 for 2
- 经过时间:16.9633134 3
- 经过时间:18.723183399999996 4
- 经过时间:21.568377299999995 5
- 经过时间:24.126758499999994 for 6
- 经过时间:29.142095499999996 for 7
- 已用时间:33.175509300000016 为 8
。 . .
- 经过的时间:44.629786800000005 for 11
- 经过的时间:46.22480710000002 for 12
- 经过的时间:50.44349420000003 for 13
- 已用时间:54.61919949999998 为 14
我不明白你想达到什么目的?
您正在做同样的工作,并且 运行 它 X 次,其中 X 是循环中 SMP 的数量。您应该接管工作并将其除以 X,然后将一个块发送到每个 SMP 单元。
无论如何,关于您所观察到的情况 - 您看到了生成和关闭单独进程所花费的时间。 Python 启动新流程的速度不快。
您的测试有误。
试想一下,一个农民用一台拖拉机耕种 10 公里^2 的农田需要 1 天。如果有两个农民在 20 公里 ^2 的农场上工作,为什么你期望两个农民使用两台拖拉机在两倍的农田上工作花费更少的时间?
你有6个CPU核心,你的村子有6台拖拉机,但是没有人有钱买私人拖拉机。随着村里工人(工序)的增加,拖拉机的数量却保持不变,大家不得不共享有限的拖拉机。
在理想世界中,两个农民使用两台拖拉机完成两倍的工作量与一个农民完成一份工作所花费的时间完全相同,但在真实的计算机中,机器甚至还有其他工作要做如果它看起来很闲。有任务切换,OS 内核必须 运行 并监控硬件设备,内存缓存需要在 CPU 个内核之间刷新和失效,你的浏览器需要 运行,村里的长老正在开会,讨论谁应该得到拖拉机,什么时候得到等等
随着工人数量的增加超过拖拉机的数量,农民不再只是独占拖拉机。相反,他们安排每三个小时左右让拖拉机经过一次。这意味着第七个农民不必等待两天就可以得到他们的拖拉机时间。然而,在农田之间转移拖拉机是有成本的,就像 CPU 在进程之间切换一样;任务切换太频繁,CPU 实际上没有工作,切换不频繁,你会资源匮乏,因为有些工作需要很长时间才能开始处理。
一个更明智的测试是保持耕地面积不变,只增加农民的数量。在您的代码中,这将对应于此更改:
def rand_val(num_workers):
num = []
for i in range(200000000 / num_workers):
num = random.random()
print('done')
def main():
for iii in range(15):
processes = [Process(target=lambda: rand_val(iii)) for _ in range(iii)]
...
你有两个错误的假设:
- 进程不是免费的。仅添加进程会增加程序的开销。
- 进程不拥有 CPUs。 CPU 交错执行多个进程。
第一点是为什么您会看到一些开销,即使进程少于 CPUs。请注意,您的系统通常有多个后台进程 运行ning,因此“少于 CPUs 的进程”这一点对于单个应用程序而言并不明确。
第二点是为什么当进程数超过CPU秒时,执行时间会逐渐增加。任何 OS 运行ning 主线 Python 都会 preemptive multitasking of processes;粗略地说,这意味着一个进程在完成之前不会阻塞 CPU,而是定期暂停以便其他进程可以 运行.
实际上,这意味着多个进程可以同时在一个 CPU 上 运行。由于 CPU 每次仍只能执行固定数量的工作,因此所有进程都需要更长的时间才能完成。