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万份KDTreetraining_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,以便在可能的时候节省开支。