1 回答
TA贡献1817条经验 获得超6个赞
构建O(N**2)未在序列化代码中使用的 3 元素字典,并通过进程间管道传输它们,是保证多处理无济于事的一种很好的方法;-) 没有什么是免费的 - 一切都需要付出代价。
下面是一个重写,无论它是在串行还是多处理模式下运行,它都会执行几乎相同的代码。没有新的 dicts 等。一般来说,越大len(coords),它从多处理中获得的好处就越多。在我的机器上,在 20000 时,多处理运行大约需要挂钟时间的三分之一。
关键是所有进程都有自己的coords. 这是通过在创建池时仅传输一次来完成的。这应该适用于所有平台。在 Linux-y 系统上,它可以通过分叉进程继承“神奇地”发生。减少跨进程发送的数据量O(N**2)来O(N)是一个巨大的进步。
充分利用多处理将需要更好的负载平衡。照原样,对 的调用check_overlap(i)与coords[i]中的每个值进行比较coords[i+1:]。越大i,越少的工作出现了为它做,并且最大值i传递的只是成本的i进程之间-而将结果发送回-沼泽耗时间在 check_overlap(i)。
def init(*args):
global _coords, _tolerance
_coords, _tolerance = args
def check_overlap(start_index):
coords, tolerance = _coords, _tolerance
tsq = tolerance ** 2
overlaps = 0
start0, start1 = coords[start_index]
for i in range(start_index + 1, len(coords)):
that0, that1 = coords[i]
dx = abs(that0 - start0)
if dx <= tolerance:
dy = abs(that1 - start1)
if dy <= tolerance:
if dx**2 + dy**2 <= tsq:
overlaps += 1
return overlaps
def process_coords(coords, num_processors=1, tolerance=1):
global _coords, _tolerance
import multiprocessing as mp
_coords, _tolerance = coords, tolerance
import time
if num_processors > 1:
pool = mp.Pool(num_processors, initializer=init, initargs=(coords, tolerance))
start = time.time()
print("Start script w/ multiprocessing")
else:
num_processors = 0
start = time.time()
print("Start script w/ standard processing")
N = len(coords)
if num_processors:
total_overlap_count = sum(pool.imap_unordered(check_overlap, range(N)))
else:
total_overlap_count = sum(check_overlap(i) for i in range(N))
print(total_overlap_count)
print(" time: {0}".format(time.time() - start))
if __name__ == "__main__":
from random import random
coords = []
num_coords = 20000
spread = 100.0
half_spread = 0.5*spread
for i in range(num_coords):
coords.append([
random()*spread-half_spread,
random()*spread-half_spread
])
process_coords(coords, 1)
process_coords(coords, 4)
添加回答
举报