Python 当函数需要大数据结构作为参数时,如何有效地使用Pool.starmap? 背景:

Python 当函数需要大数据结构作为参数时,如何有效地使用Pool.starmap? 背景:,python,parallel-processing,python-multiprocessing,pool,kdtree,Python,Parallel Processing,Python Multiprocessing,Pool,Kdtree,我接管了一个笔记本中的一些代码,该笔记本大量使用全局变量,这一方面使使用Pool.imap变得容易,但另一方面也使阅读、调试和从jupyter笔记本移到现实世界变得困难: 此方法只需调用另一个方法query\u rec,在给定点周围执行KNN搜索。请注意,点_调整和时间是在函数之外定义的query_rec使用在其范围之外定义的KDTree: def get_neighbors(i): point = points_adjusted[i] + (times[i],) temp =

我接管了一个笔记本中的一些代码,该笔记本大量使用全局变量,这一方面使使用
Pool.imap变得容易,但另一方面也使阅读、调试和从jupyter笔记本移到现实世界变得困难:

此方法只需调用另一个方法
query\u rec
,在给定点周围执行KNN搜索。请注意,
点_调整
时间
是在函数之外定义的
query_rec
使用在其范围之外定义的
KDTree

def get_neighbors(i):
    point = points_adjusted[i] + (times[i],)
    temp = query_rec(point, INPUT_EVENT_COUNT, 2)
    return temp

def query_rec(point, k, rk):
    # KNN SEARCH... TOO MUCH CODE AND DOESNT MATTER FOR THE QUESTION

sorted_training_data = [t for t in pool.imap(get_neighbors, np.arange(num_points) if t]
我想要达到的目标: 我想重构
get_neights
query_rec
以不使用全局变量,但仍然能够使用多重处理

我的尝试第1部分: 我重构了上述函数,以便它们将全局变量作为参数:

def get_neighbors(points, tree, i, k=INPUT_EVENT_COUNT):
    point = points[i]
    temp = query_rec(point, tree, k, 2)
    return temp
接下来,我必须创建一个iterable,其中包含我要传递给新重构函数的所有参数:

pool = Pool(NUM_WORKERS)
args = zip([points] * num_points, [training_tree] * num_points, np.arange(num_points))
sorted_training_data = [t for t in pool.starmap(get_neighbors, args) if t]
我的解决方案的问题:
points
中大约有300万个点,我正在制作300万份KDTree
training_tree
。这对我来说真的很糟糕

我试过的第2部分: 我尝试将我想要的功能封装在一个新的数据结构中,如下所示:

class TimeTree:
    """
    A data structure combining a KDTree and a uniform gridspace of points for efficeient NN searches.
    """
    def __init__(self, kdtree, grid_points):
        """
        :param kdtree: a KDTree containing event data points in the form (lat, lng, time)
        :param grid_points: A uniform gridspace of (lat, lng, time) points 
        """
        self.tree = kdtree
        self.points = grid_points
        self.size = len(grid_points)
        
    def search(self, idx, k, rk=2):
        """
        A function designed to be used with a multiprocess.pool to perform a global KNN search
        of all points in the ``self.points`` list.
        :param idx: The index of the point to search around.
        :param k: The number of neighbors to search for.
        :param rk: A recursive constant for extended search capabilites.
        """
        return query_rec(self.points[idx], self.tree, k, rk)      
然后创建一个助手函数来生成数据:

def generate_data(k, t, workers=NUM_WORKERS):
    args = zip(np.arange(t.size), [k] * t.size)
    with Pool(workers) as p:
        data = [d for d in tqdm(p.starmap(t.search, args), total=t.size) if d]
    return data
我读到这是一个解决
Pool
对象在使用
Pool.map
时出现pickle问题的方法。我相信这可能有效,除非我在
query\u rec
定义中发现了另一个我以前没有注意到的全局变量。这可能是一个解决方案,我稍后会更新

问题是:
如何有效地对以大型数据结构为参数的函数使用多重处理?

实际上,我建议您使用functools中的部分模块,这对我有很大帮助:

from functools import partial

def f(x, y, a, b, c, d):
  # important: abcd variables should be at the right
  return x + y + a + b + c + d
    
f_of_x = partial(f, a=5, b=10, c=15, d=20) 
f_of_x您可以传递到池星图(f_of_x,zip(x,Y))

此外,您还可以从另一个带有常量的文件中导入abcd的所有值。但要小心:如果执行带有导入全局变量的池,它不会在原始文件中更新或更改它们(它的工作方式很奇怪),也不会pickle lambdas


实际上,在Python中,您可能会遇到很多与池和其他多处理相关的问题,有时很难找到答案。其中一些可以通过不同的或相关的Google查询找到,祝你好运:)

我假设你是在linux/mac而不是windows这样的分叉系统上做的,这样子进程在创建时就可以看到父内存?@tdelaney我在这两个系统上都做了。我在必要的时候在云上使用linux,但在我的个人笔记本电脑上尽可能多地使用linux,以便在可能的时候节省开支。