【问题标题】:How to multiprocess for loops in python where each calculation is independent?如何在每个计算独立的python中对循环进行多处理?
【发布时间】:2020-02-21 23:30:39
【问题描述】:

我正在尝试在我所做的每个迷你项目中学习一些新的东西。我制作了一个生命游戏(https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life)程序。

这涉及一个 numpy 数组,其中数组中的每个点(“单元格”)都有一个整数值。要演化游戏状态,您必须为每个单元计算其所有相邻值(8 个相邻值)的总和。

我的代码中的相关类如下,其中evolve() 采用xxx_method 方法之一。它适用于conv_methodloop_method,但我想在loop_method 上使用多处理(我已经确定它应该可以工作,不像多线程?)来查看任何性能提升。我觉得它应该起作用,因为每个计算都是独立的。我尝试了一种天真的方法,但对多处理模块的理解还不够好。我是否也可以在evolve() 方法中使用它,因为我再次觉得双for 循环中的每个计算都是独立的。

任何帮助表示赞赏,包括通用代码 cmets。

编辑 - 我收到了一个 RuntimeError,因为我对多处理的理解不够好,所以我有一半的预期。需要对代码执行什么操作才能使其正常工作?

class GoL:
    """ Game Engine """
    def __init__(self, size):
        self.size = size
        self.grid = Grid(size) # Grid is another class ive defined

    def evolve(self, neigbour_sum_func):
        new_grid = np.zeros_like(self.grid.cells) # start with everything dead, only need to test for keeping/turning alive
        neighbour_sum_array = neigbour_sum_func()
        for i in range(self.size):
            for j in range(self.size):
                cell_sum = neighbour_sum_array[i,j]
                if self.grid.cells[i,j]: # already alive
                    if cell_sum == 2 or cell_sum == 3:
                        new_grid[i,j] = 1
                else: # test for dead coming alive
                    if cell_sum == 3:
                        new_grid[i,j] = 1

        self.grid.cells = new_grid

    def conv_method(self):
        """ Uses 2D convolution across the entire grid to work out the neighbour sum at each cell """
        kernel = np.array([
                            [1,1,1],
                            [1,0,1],
                            [1,1,1]],
                            dtype=int)
        neighbour_sum_grid = correlate2d(self.grid.cells, kernel, mode='same')
        return neighbour_sum_grid

    def loop_method(self, partition=None):
        """ Also works out neighbour sum for each cell, using a more naive loop method """
        if partition is None:
            cells = self.grid.cells # no multithreading, just work on entire grid
        else:
            cells = partition # just work on a set section of the grid

        neighbour_sum_grid = np.zeros_like(cells) # copy
        for i, row in enumerate(cells):
            for j, cell_val in enumerate(row):
                neighbours = cells[i-1:i+2, j-1:j+2]
                neighbour_sum = np.sum(neighbours) - cell_val
                neighbour_sum_grid[i,j] = neighbour_sum
        return neighbour_sum_grid

    def multi_loop_method(self):
        cores = cpu_count()
        procs = []
        slices = []
        if cores == 2: # for my VM, need to impliment generalised method for more cores
            half_grid_point = int(SQUARES / 2)
            slices.append(self.grid.cells[0:half_grid_point])
            slices.append(self.grid.cells[half_grid_point:])
        else:
            Exception

        for sl in slices:
            proc = Process(target=self.loop_method, args=(sl,))
            proc.start()
            procs.append(proc)

        for proc in procs:
            proc.join()

【问题讨论】:

    标签: python optimization multiprocessing conways-game-of-life


    【解决方案1】:

    我想使用多处理(我已经确定它应该可以工作,不像多线程?)

    多线程无法工作,因为它会在单个处理器上运行,这是您当前的瓶颈。多线程用于等待 API 回答的事情。在此期间,您可以进行其他计算。但在康威的生命游戏中,你的程序一直在运行。


    正确进行多处理很难。如果您有 4 个处理器,您可以为每个处理器定义一个象限。但是您需要在处理器之间共享结果。有了这个,你的性能就会受到影响。它们需要同步/以相同的时钟速度运行/具有相同的更新速率,并且需要共享结果。

    当您的网格非常大/需要计算大量数据时,多处理开始变得可行。
    由于这个问题非常广泛和复杂,我无法给你更好的答案。有一篇关于 Conway's Game of Life 获得并行处理的论文:http://www.shodor.org/media/content/petascale/materials/UPModules/GameOfLife/Life_Module_Document_pdf.pdf

    【讨论】:

    • 谢谢!我已经编辑了我的原始代码,开始处理网格的离散分区 - 我的新问题是如何让它工作?
    猜你喜欢
    • 2023-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-07
    • 1970-01-01
    • 2023-03-17
    相关资源
    最近更新 更多