我正在尝试学习如何在 Python 中使用多处理。 我读到了 multiprocessing ,我想做这样的事情:
我有以下类(部分代码),它有一个生成 voronoi 图的方法:
class ImageData:
def generate_voronoi_diagram(self, seeds):
"""
Generate a voronoi diagram with *seeds* seeds
:param seeds: the number of seed in the voronoi diagram
"""
nx = []
ny = []
gs = []
for i in range(seeds):
# Generate a cell position
pos_x = random.randrange(self.width)
pos_y = random.randrange(self.height)
nx.append(pos_x)
ny.append(pos_y)
# Save the f(x,y) data
x = Utils.translate(pos_x, 0, self.width, self.range_min, self.range_max)
y = Utils.translate(pos_y, 0, self.height, self.range_min, self.range_max)
z = Utils.function(x, y)
gs.append(z)
for y in range(self.height):
for x in range(self.width):
# Return the Euclidean norm
d_min = math.hypot(self.width - 1, self.height - 1)
j = -1
for i in range(seeds):
# The distance from a cell to x, y point being considered
d = math.hypot(nx[i] - x, ny[i] - y)
if d < d_min:
d_min = d
j = i
self.data[x][y] = gs[j]
我要生成大量这样的图,所以,这会消耗很多时间,所以我认为这是一个典型的并行化问题。 我是这样做的,在“正常”的方法中,像这样:
if __name__ == "__main__":
entries = []
for n in range(images):
entry = ImD.ImageData(width, height)
entry.generate_voronoi_diagram(seeds)
entry.generate_heat_map_image("ImagesOutput/Entries/Entry"+str(n))
entries.append(entry)
为了并行化,我尝试了这个:
if __name__ == "__main__":
entries = []
seeds = np.random.poisson(100)
p = Pool()
entry = ImD.ImageData(width, height)
res = p.apply_async(entry.generate_voronoi_diagram,(seeds))
entries.append(entry)
entry.generate_heat_map_image("ImagesOutput/Entries/EntryX")
但是,除了连生成一张图都行不通之外,我不知道如何指定必须生成 N 次。
任何帮助将不胜感激。 谢谢。
请您参考如下方法:
Python 的多进程不共享内存(除非你明确告诉它)。这意味着您不会看到在工作进程中运行的任何函数的“副作用”。您的 generate_voronoi_diagram 方法通过将数据添加到 entry 值来工作,这是一种副作用。为了查看结果,您需要将其作为函数的返回值传回。
这是一种将 entry 实例作为参数和返回值处理的方法:
def do_voroni(entry, seeds):
entry.generate_voronoi_diagram(seeds)
return entry
现在,您可以在工作进程中使用此功能:
if __name__ == "__main__":
entries = [ImD.ImageData(width, height) for _ in range(images)]
seeds = numpy.random.poisson(100, images) # array of values
pool = multiprocessing.Pool()
for i, e in enumerate(pool.starmap_async(do_voroni, zip(entries, seeds))):
e.generate_heat_map_image("ImagesOutput/Entries/Entry{:02d}".format(i))
循环中的 e 值不是对 entries 列表中值的引用。相反,它们是那些对象的副本,这些对象已传递给工作进程(向它们添加数据),然后传回。
