我正在尝试此代码,并且运行良好,但是速度很慢,因为迭代次数很高。
我在考虑线程,那应该提高此脚本的性能,对吗?好吧,问题是我如何才能更改此代码以使其与同步线程一起使用。
def get_duplicated(self):
db_pais_origuem = self.country_assoc(int(self.Pais_origem))
db_pais_destino = self.country_assoc(int(self.Pais_destino))
condicao = self.condition_assoc(int(self.Condicoes))
origem = db_pais_origuem.query("xxx")
destino = db_pais_destino.query("xxx")
origem_result = origem.getresult()
destino_result = destino.getresult()
for i in origem_result:
for a in destino_result:
text1 = i[2]
text2 = a[2]
vector1 = self.text_to_vector(text1)
vector2 = self.text_to_vector(text2)
cosine = self.get_cosine(vector1, vector2)
origem_result和destino_result结构:
[(382360, 'name abcd', 'some data'), (361052, 'name abcd', 'some data'), (361088, 'name abcd', 'some data')]
最佳答案
据我所知,您正在计算向量对之间的距离函数。给定向量列表v1,...,vn和第二个列表w1,... wn,您想要v和w的所有对之间的距离/相似度。这通常非常适合并行计算,有时也称为尴尬的并行计算。 IPython为此很好地工作。
如果您的距离函数distance(a,b)是独立的,并且不依赖于其他距离函数值的结果(通常是我所见的情况),那么您可以轻松地使用ipython并行计算工具箱。我建议在线程,队列等上使用它,以完成各种任务,尤其是探索性任务。但是,可以将相同的原理扩展到python中的线程或队列模块。
我建议跟随http://ipython.org/ipython-doc/stable/parallel/parallel_intro.html#parallel-overview和http://ipython.org/ipython-doc/stable/parallel/parallel_task.html#quick-and-easy-parallelism一起使用。它为并行化提供了一个非常简单,温和的介绍。
在简单的情况下,您只需使用计算机(或网络,如果您想提高速度)上的线程,并让每个线程计算尽可能多的距离(a,b)。
假设可以看到ipcluster可执行命令类型的命令提示符
ipcluster start -n 3
这将启动集群。您将要根据自己的具体情况调整内核/线程数。考虑使用n-1个内核,以允许一个内核处理调度。
Hello World 示例如下:
serial_result = map(lambda z:z**10, range(32))
from IPython.parallel import Client
rc = Client()
rc
rc.ids
dview = rc[:] # use all engines
parallel_result = dview.map_sync(lambda z: z**10, range(32))
#a couple of caveats, are this template will not work directly
#for our use case of computing distance between a matrix (observations x variables)
#because the allV data matrix and the distance function are not visible to the nodes
serial_result == parallel_result
为了简单起见,我将展示如何计算allV中指定的所有向量对之间的距离。假设每一行代表一个具有三个维度的数据点(观测)。
同样,我也不会以“教学上的错误”的方式来介绍这种方式,而是我偶然发现的方式与远程节点上的功能和数据的可见性产生了冲突。我发现这是进入的最大障碍
dataPoints = 10
allV = numpy.random.rand(dataPoints,3)
mesh = list(itertools.product(arange(dataPoints),arange(dataPoints)))
#given the following distance function we can evaluate locally
def DisALocal(a,b):
return numpy.linalg.norm(a-b)
serial_result = map(lambda z: DisALocal(allV[z[0]],allV[z[1]]),mesh)
parallel_result = dview.map_sync(lambda z: DisALocal(allV[z[0]],allV[z[1]]),mesh)
#will not work as DisALocal is not visible to the nodes
#also will not work as allV is not visible to the nodes
有几种定义远程功能的方法。
取决于我们是否要将数据矩阵发送到节点。
是否要矩阵有多大的取舍
将大量向量分别发送到节点或发送整个矩阵
前期...
#in first case we send the function def to the nodes via autopx magic
%autopx
def DisARemote(a,b):
import numpy
return numpy.linalg.norm(a-b)
%autopx
#It requires us to push allV. Also note the import numpy in the function
dview.push(dict(allV=allV))
parallel_result = dview.map_sync(lambda z: DisARemote(allV[z[0]],allV[z[1]]),mesh)
serial_result == parallel_result
#here we will generate the vectors to compute differences between
#and pass the vectors only, so we do not need to load allV across the
#nodes. We must pre compute the vectors, but this could, perhaps, be
#done more cleverly
z1,z2 = zip(*mesh)
z1 = array(z1)
z2 = array(z2)
allVectorsA = allV[z1]
allVectorsB = allV[z2]
@dview.parallel(block=True)
def DisB(a,b):
return numpy.linalg.norm(a-b)
parallel_result = DisB.map(allVectorsA,allVectorsB)
serial_result == parallel_result
在最后的情况下,我们将执行以下操作
#this relies on the allV data matrix being pre loaded on the nodes.
#note with DisC we do not import numpy in the function, but
#import it via sync_imports command
with dview.sync_imports():
import numpy
@dview.parallel(block=True)
def DisC(a):
return numpy.linalg.norm(allV[a[0]]-allV[a[1]])
#the data structure must be passed to all threads
dview.push(dict(allV=allV))
parallel_result = DisC.map(mesh)
serial_result == parallel_result
以上所有内容都可以轻松地扩展以负载均衡的方式工作
当然,最简单的加速(假设distance(a,b)= distance(b,a))如下。它只会将运行时间缩短一半,但可以与上述并行化思想一起使用,以仅计算距离矩阵的上三角。
for vIndex,currentV in enumerate(v):
for wIndex,currentW in enumerate(w):
if vIndex > wIndex:
continue#we can skip the other half of the computations
distance[vIndex,wIndex] = get_cosine(currentV, currentW)
#if distance(a,b) = distance(b,a) then use this trick
distance[wIndex,vIndex] = distance[vIndex,wIndex]