使用线程提高脚本的速度

2024-04-26 01:24:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试这段代码,它工作得很好,但是非常慢,因为迭代次数很高。你知道吗

我在考虑线程,这应该会提高这个脚本的性能,对吗?好吧,问题是我如何才能改变这段代码,使之与同步线程一起工作。你知道吗

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)

原始结果和目的结果结构:

[(382360, 'name abcd', 'some data'), (361052, 'name abcd', 'some data'), (361088, 'name abcd', 'some data')]

Tags: 代码nameselfdbdatagetsomeresult
1条回答
网友
1楼 · 发布于 2024-04-26 01:24:25

据我所见,你正在计算向量对之间的距离函数。给定一个向量列表v1,…,vn和第二个列表w1,…,wn,您需要v和w的所有对之间的距离/相似性。这通常非常适合并行计算,有时被称为令人尴尬的并行计算。IPython在这方面做得很好。你知道吗

如果距离函数distance(a,b)是独立的,并且不依赖于其他距离函数值的结果(这通常是我看到的情况),那么就可以轻松地使用ipython并行计算工具箱。我建议在线程、队列等上使用它。。。各种各样的任务,特别是探索性的。但是,同样的原则可以扩展到python中的线程或队列模块。你知道吗

我建议您跟随http://ipython.org/ipython-doc/stable/parallel/parallel_intro.html#parallel-overviewhttp://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

所有这些都可以很容易地扩展到以负载平衡的方式工作

当然,最简单的加速(假设距离(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]

相关问题 更多 >