问题描述
背景:
我在笔记本中接管了一些代码,这些笔记本大量使用了全局变量,一方面使使用Pool.imap
变得容易,但另一方面却使其难以阅读,调试和移出一个Jupyter笔记本进入现实世界:
此方法仅调用另一个方法query_rec
即可在给定点周围执行KNN搜索。请注意,points_adjusted
和times
是在函数外部定义的。 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_neighbors
和query_rec
以不使用全局变量,但仍然可以使用多重处理。
我尝试的第1部分:
def get_neighbors(points,tree,i,k=INPUT_EVENT_COUNT):
point = points[i]
temp = query_rec(point,2)
return temp
在此之后,我必须进行迭代,以包含要传递给新重构的函数的所有参数:
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
。这对我来说真的很糟糕。
我尝试过的第二部分:
我尝试将所需的功能封装在新的数据结构中,如下所示:
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,time) points
"""
self.tree = kdtree
self.points = grid_points
self.size = len(grid_points)
def search(self,idx,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,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
个对象的解决方案。我相信这可能行得通,除了在query_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 传递给Pool starmap(f_of_x,zip(X,Y))。
您还可以从另一个带有常量的文件中导入 abcd 的所有值。但请注意:带有导入的全局变量的池将不会在原始文件中更新或更改(如果执行)(它的工作方式很怪异),也不会腌制lambda。
实际上,您可能会遇到许多与Pool和Python中的其他多处理相关的问题,有时很难找到答案。其中一些可以通过其他或相关的Google查询找到,祝您好运:)