2

我正在尝试学习如何在 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 次。

任何帮助将不胜感激。谢谢。

4

2 回答 2

1

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列表中值的引用。相反,它们是这些对象的副本,这些对象已传递给工作进程(向它们添加数据),然后再传回。

于 2013-10-17T15:30:28.177 回答
0

我可能是错的,但我认为你应该使用

res = p.apply_async(entry.generate_voronoi_diagram,(种子))

res.get(超时=1)

你可能会得到 Can't pickle type 'instancemethod'

我认为最简单的方法是

import random
from multiprocessing import Pool


class ImageData:

    def generate_voronoi_diagram(self, seeds):
        ooxx

    def generate_heat_map_image(self, path):
        ooxx

def allinone(obj, seeds, path):
    obj.generate_voronoi_diagram(seeds)
    obj.generate_heat_map_image(path)

if __name__ == "__main__":
    entries = []
    seeds = random.random()
    p = Pool()
    entry = ImageData()
    res = p.apply_async(allinone, (entry, seeds, 'tmp.txt'))
    res.get(timeout=1)   
于 2013-10-17T15:26:19.090 回答