from multiprocessing import Pool
def op1(data):
return [data[elem] + 1 for elem in range(len(data))]
data = [[elem for elem in range(20)] for elem in range(500000)]
import time
start_time = time.time()
re = []
for data_ in data:
re.append(op1(data_))
print('--- %s seconds ---' % (time.time() - start_time))
start_time = time.time()
pool = Pool(processes=4)
data = pool.map(op1, data)
print('--- %s seconds ---' % (time.time() - start_time))
我使用池的运行时间比循环使用要慢得多。但是不是池应该使用4个处理器并行进行计算吗?
答案 0 :(得分:9)
简答:是,操作通常在可用内核(的一部分)上完成。但通信开销很大。 在您的示例中,工作量与开销相比太小。
如果您构建了一个池,将构建一些 worker 。如果您然后指示map
给定输入。发生以下情况:
现在,拆分,通信和连接数据是主进程执行的所有进程。这些无法并行化。由于操作速度很快( O(n)且输入大小 n ),因此开销具有相同的时间复杂度。
即使你拥有数百万个核心,这也很复杂,因为传播列表可能比计算结果更昂贵。
这就是为什么你应该并行化计算成本高昂的任务。不是简单的任务。与通信量相比,处理量应大。
在您的示例中,工作琐事:您将1添加到所有元素。然而,序列化不那么重要:您必须对发送给工作人员的列表进行编码。
答案 1 :(得分:3)
您的代码存在一些潜在的问题,但主要是它太简单了。
multiprocessing
模块通过创建不同的进程并在它们之间进行通信来工作。对于创建的每个进程,您必须支付操作系统的进程启动成本以及python启动成本。这些成本可能很高或很低,但在任何情况下它们都不为零。
一旦您支付了这些启动成本,就可以pool.map
所有流程中的工作人员功能。这基本上增加了1到几个数字。正如您的测试证明的那样,这不是一个重要的负载。
更糟糕的是,您正在使用隐式排序的.map()
(与.imap_unordered()
比较),因此正在进行同步 - 为各种CPU内核留下更少的自由度来提高速度。< / p>
如果这里出现问题,那就是“实验设计”问题 - 你没有为multiprocessing
创建一个足够困难的问题来帮助你。
答案 2 :(得分:1)
正如其他人所指出的那样,为促进多处理而付出的开销超过了在多个内核之间并行化所节省的时间。换句话说,您的函数op1()
不需要足够的CPU资源即可看到并行化带来的性能提升。
在multiprocessing.Pool
类中,大部分窃听是在数据在父进程(创建池的)和子级“ worker”之间穿梭之前花费的,对数据进行序列化和反序列化
This blog post详细探讨了使用pickling
模块时multiprocessing.Pool
(序列化)的价格。