我正在尝试使用此代码,但它运行良好,但速度非常慢,因为迭代次数很多。
我正在考虑线程,这应该会提高这个脚本的性能,对吧?好吧,问题是如何更改此代码以使用同步线程。
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')]
答案 0 :(得分:1)
从我所看到的,你正在计算矢量对之间的距离函数。给定一个向量列表,v1,...,vn和第二个列表w1,...你想要v和w之间的所有对之间的距离/相似性。这通常非常适合于并行计算,并且有时被称为令人尴尬的并行计算。 IPython对此非常有效。
如果您的距离函数距离(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中指定的所有向量对之间的距离。假设每行表示具有三个维度的数据点(观察)。
此外,我不打算以“pedagoically corret”的方式呈现这种方式,但是我偶然发现它与我在远程节点上的功能和数据的可见性进行了斗争。我发现这是进入的最大障碍
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
以上所有内容都可以轻松扩展,以负载均衡的方式工作
当然,最简单的加速(假设距离(a,b)=距离(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]