Python多处理:检查内存是共享的还是被复制的
我必须从sklearn KDTree中查询大量向量,这是searcher类的路径。我尝试使用python多处理并行查询它们,但是并行代码所花费的时间几乎与单个版本相同(或更多)Python多处理:检查内存是共享的还是被复制的,python,python-multithreading,python-multiprocessing,pathos,Python,Python Multithreading,Python Multiprocessing,Pathos,我必须从sklearn KDTree中查询大量向量,这是searcher类的路径。我尝试使用python多处理并行查询它们,但是并行代码所花费的时间几乎与单个版本相同(或更多) import time, numpy as np from sklearn.neighbors import KDTree from multiprocessing import Pool def glob_query(arg, **kwarg): return Searcher.query(*arg, **k
import time, numpy as np
from sklearn.neighbors import KDTree
from multiprocessing import Pool
def glob_query(arg, **kwarg):
return Searcher.query(*arg, **kwarg)
class Searcher:
def __init__(self, N, D):
self.kdt = KDTree(np.random.rand(N,D), leaf_size=30, metric="euclidean")
def query(self, X):
return self.kdt.query(X, k=5, return_distance=False)
def query_sin(self, X):
return [self.query(x) for x in X]
def query_par(self, X):
p = Pool(4)
return p.map(glob_query, zip([self]*len(X), X))
if __name__=="__main__":
N = 1000000 # Number of points to be indexed
D = 50 # Dimensions
searcher = Searcher(N, D)
E = 100 # Number of points to be searched
points = np.random.rand(E, D)
# Works fine
start = time.time()
searcher.query_sin(points)
print("Time taken - %f"%(time.time()-start))
# Slower than single core
start = time.time()
print searcher.query_par(points)
print("Time taken - %f"%(time.time()-start))
Time taken - 28.591089
Time taken - 36.920716
我想知道
- 如果我的kd树是跨每个工作线程复制的
- 有没有其他方法可以并行搜索(使用pathos?)
或者您可以使用
imap
或imap\u unordered
返回结果的迭代器。在启动imap
之前打印时间。在query
方法中打印运行查询前后的当前时间。还打印迭代器生成结果的时间。这应该能让您了解程序大部分时间都花在哪里。池启动的进程基本上是当时父进程的副本。因为您在池之前创建kd树,所以所有子级都应该有kd树
请注意,创建新进程需要时间和内存
每次映射函数返回结果时,都会使用IPC将结果发送回父进程。根据返回的数据的大小,这可能会有很大的开销
但是在你尝试改进之前,先测量一下。如果不知道问题的原因,就无法解决问题
您可以使用探查器查看程序在何处花费时间
或者您可以使用
imap
或imap\u unordered
返回结果的迭代器。在启动imap
之前打印时间。在query
方法中打印运行查询前后的当前时间。还打印迭代器生成结果的时间。这会让你知道程序大部分时间都花在哪里。你的代码看起来不错。我猜额外的时间来自于在池中创建4个进程。尝试在搜索者的init方法中创建池,看看是否确实如此
关于您的问题,当您打开一个新进程时,传递的对象将复制到新进程
如果在Windows中运行,那么启动的每个进程都会导致python在新进程中重新导入所有代码,并对变量进行pickle以复制它们(对于短期运行的进程来说,这可能会很昂贵)
在linux中,所有这一切都被os.fork所取代,您的代码看起来很好。我猜额外的时间来自于在池中创建4个进程。尝试在搜索者的init方法中创建池,看看是否确实如此 关于您的问题,当您打开一个新进程时,传递的对象将复制到新进程 如果在Windows中运行,那么启动的每个进程都会导致python在新进程中重新导入所有代码,并对变量进行pickle以复制它们(对于短期运行的进程来说,这可能会很昂贵)
在linux中,所有这些都被os.fork所取代,我是pathos的作者。如其他答案所述,
多处理
将对象复制到新进程。pathos
的情况也是如此,因为它建立在多处理的分支上pathos
可以帮助您:(1)它将提供更好的序列化,(2)可以接受多个参数的更灵活的map
,以及(3)在启动多个池时消除一些开销
…但这听起来不像您的情况
如果单独的计算非常简单,那么多处理.dummy
中的线程可能是更好的方法。你可以试试看,看看它是否能加快速度。界面是相同的,因此代码中几乎没有可编辑的内容。另外,正如其他人所建议的,如果您不需要维护结果的顺序,imap\u unordered
通常是池中映射
函数中速度最快的
通常,最好的做法是尝试几种地图
,看看哪种最适合你的情况。我是悲情
的作者。如其他答案所述,多处理
将对象复制到新进程。pathos
的情况也是如此,因为它建立在多处理的分支上pathos
可以帮助您:(1)它将提供更好的序列化,(2)可以接受多个参数的更灵活的map
,以及(3)在启动多个池时消除一些开销
…但这听起来不像您的情况
如果单独的计算非常简单,那么多处理.dummy
中的线程可能是更好的方法。你可以试试看,看看它是否能加快速度。界面是相同的,因此代码中几乎没有可编辑的内容。另外,正如其他人所建议的,如果您不需要维护结果的顺序,imap\u unordered
通常是池中映射
函数中速度最快的
通常最好的做法是尝试几种map
,看看哪种最适合您的情况。如果我在init
中创建池,我会收到一个错误,说pool o