我在具有4 GB核心(8线程超线程)的Intel i7上并行生成大约400,000,000(4亿)个随机数,并且内存为8 GB。
但是,我还在DigitalOcean服务器上生成了400,000,000个随机数,其中Debian上有20个内核,内存为64 GB。
以下是代码:
import multiprocessing
import random
rangemin = 1
rangemax = 9
def randomGenPar_backend(backinput):
return random.randint(rangemin, rangemax)
def randomGenPar(num):
pool = multiprocessing.Pool()
return pool.map(randomGenPar_backend, range(0, num))
randNum = 400000000
random.seed(999)
randomGenPar(randNum)
这些是基准测试的结果:
5,000,000 Random Numbers:
1 Core: 5.984
8 Core: 1.982
50,000,000 Random Numbers:
1 Core: 57.28
8 Core: 19.799
20 Core: 18.257
Times Benefit (20 core vs. 8 core) = 1.08
100,000,000 Random Numbers:
1 Core: 115
8 Core: 40.434
20 Core: 31.652
Times Benefit (20 core vs. 8 core) = 1.28
200,000,000 Random Numbers:
8 Core: 87
20 Core: 60
Times Benefit (20 core vs. 8 core) = 1.45
300,000,000 Random Numbers:
8 Core: 157
20 Core: 88
Times Benefit (20 core vs. 8 core) = 1.78
400,000,000 Random Numbers:
8 Core: 202
20 Core: 139
Times Benefit (20 core vs. 8 core) = 1.45 (DIP!)
500,000,000 Random Numbers:
8 Core: 280
20 Core: 171
Times Benefit (20 core vs. 8 core) = 1.64 (INCREASE!)
600,000,000 Random Numbers:
8 Core: 342
20 Core: 198
Times Benefit (20 core vs. 8 core) = 1.73
700,000,000 Random Numbers:
8 Core: 410
20 Core: 206
Times Benefit (20 core vs. 8 core) = 1.99
800,000,000 Random Numbers:
8 Core: 482
20 Core: 231
Times Benefit (20 core vs. 8 core) = 2.09
通常,生成的随机数越多,可以使用20核CPU的并行性越多。因此,"时间增加"从8核到20核的速度随着时间的推移而增加。
然而,在3亿随机数后,这个数字会减少,并再次增加,直到8亿(我还没有进一步测试)。
这是为什么?有具体原因吗?它只是随机的吗? (我已经重复了两次,并且两次得到了相同的结果)
编辑:如果它有任何区别,我使用time
函数来计算脚本的执行时间。此外,两台机器上的操作系统都不一样(8核 - macOS,20核 - Debian)。
答案 0 :(得分:1)
我想到了两种可能的解释。
这可能是垃圾收集的一个神器。一个简单的实验就是关闭GC并查看“dip”是否仍然存在:
>>> import gc
>>> gc.disable()
另一种可能性是,这是使用 realloc()在引擎盖下的列表增长的工件。实现的列表是固定长度的指针数组。当 map()使用 append()增加列表时,会定期调用C函数调用 realloc()以调整指针数组的大小。通常,这种调用非常便宜,因为不需要移动任何数据。但是,如果内存中的单个字节“阻碍”调整大小,则必须重新定位所有数据。这是非常昂贵的,并且如果在执行多处理中创建阻塞字节的那一点,可能会导致“下降”。
要测试此假设,您可以使用 imap()而不是 map()并将结果反馈到 collections.deque()而不是 list()。 deque实现不使用 relloc ,因此在面对碎片化内存时它的性能是一致的(在内部,它只是重复调用 malloc()来获取固定长度的内存块)。