使python代码运行得更快

时间:2013-05-22 14:16:36

标签: python performance optimization

我有以下代码:

for stepi in range(0, nsteps): #number of steps (each step contains a number of frames)
    stepName = odb.steps.values()[stepi].name #step name
    for framei in range(0, len(odb.steps[stepName].frames)): #loop over the frames of stepi
        for v in odb.steps[stepName].frames[framei].fieldOutputs['UT'].values: #for each framei get the displacement (UT) results for each node
            for line in nodes: #nodes is a list with data of nodes (nodeID, x coordinate, y coordinate and z coordinate)
                nodeID, x, y, z = line
                if int(nodeID)==int(v.nodeLabel): #if nodeID in nodes = nodeID in results
                    if float(x)==float(coordXF) and float(y)==float(coordYF): #if x=predifined value X and y=predifined value Y
                        #Criteria 1: Find maximum displacement for x=X and y=Y
                        if abs(v.data[0]) >uFmax: #maximum UX
                            uFmax=abs(v.data[0])
                            tuFmax='U1'
                            stepuFmax=stepi
                            nodeuFmax=v.nodeLabel
                            incuFmax=framei
                        if abs(v.data[1]) >uFmax: #maximum UY
                            uFmax=abs(v.data[1])
                            tuFmax='U2'
                            stepuFmax=stepi
                            nodeuFmax=v.nodeLabel
                            incuFmax=framei
                        if abs(v.data[2]) >uFmax: #maximum UZ
                            uFmax=abs(v.data[2])
                            tuFmax='U3'
                            stepuFmax=stepi
                            nodeuFmax=v.nodeLabel 
                            incuFmax=framei
                        #Criteria 2: Find maximum  UX, UY, UZ displacement for x=X and y=Y    
                        if abs(v.data[0]) >u1Fmax: #maximum UX
                            u1Fmax=abs(v.data[0])
                            stepu1Fmax=stepi
                            nodeu1Fmax=v.nodeLabel
                            incu1Fmax=framei
                        if abs(v.data[1]) >u2Fmax: #maximum UY
                            u2Fmax=abs(v.data[1])
                            stepu2Fmax=stepi
                            nodeu2Fmax=v.nodeLabel
                            incu2Fmax=framei
                        if abs(v.data[2]) >u3Fmax: #maximum UZ
                            u3Fmax=abs(v.data[2])
                            stepu3Fmax=stepi
                            nodeu3Fmax=v.nodeLabel 
                            incu3Fmax=framei 
            #Criteria 3: Find maximum  U displacement            
            if abs(v.data[0]) >umax: #maximum UX
                umax=abs(v.data[0])
                tu='U1'
                stepumax=stepi
                nodeumax=v.nodeLabel
                incumax=framei
            if abs(v.data[1]) >umax: #maximum UY
                umax=abs(v.data[1])
                tu='U2'
                stepumax=stepi
                nodeumax=v.nodeLabel
                incumax=framei
            if abs(v.data[2]) >umax: #maximum UZ
                umax=abs(v.data[2])
                tu='U3'
                stepumax=stepi
                nodeumax=v.nodeLabel 
                incumax=framei
            #Criteria 4: Find maximum  UX, UY, UZ displacement    
            if abs(v.data[0]) >u1max: #maximum UX
                u1max=abs(v.data[0])
                stepu1max=stepi
                nodeu1max=v.nodeLabel
                incu1max=framei
            if abs(v.data[1]) >u2max: #maximum UY
                u2max=abs(v.data[1])
                stepu2max=stepi
                nodeu2max=v.nodeLabel
                incu2max=framei
            if abs(v.data[2]) >u3max: #maximum UZ
                u3max=abs(v.data[2])
                stepu3max=stepi
                nodeu3max=v.nodeLabel 
                incu3max=framei 

此代码访问由数值分析程序创建的结果数据库文件,并在给定某些不同标准的情况下检索土木工程结构的变形形状的最大位移。 问题是此代码运行大约需要10分钟。步骤nsteps的数量可以是1到4,帧数(framei)可以大于2000并且nodes的数量可以大于10000。 有没有办法让这段代码更快?

5 个答案:

答案 0 :(得分:3)

你说你有4个步骤,2000个帧和10000个节点。根据这些数字,这里有一些想法:

在节点循环之外移动计算。如果某个值不随节点变化,请在进入节点循环之前使用该值进行计算。

考虑节点的不同数据结构。对于所有8000个步骤帧,您将遍历整个节点列表。但是,您只关心满足基于nodeIDxy的两个条件测试的节点。如果您可以直接查找所需的节点,可能会更快。例如:

nodesDict[(nodeID, x, y)] = List of nodes with same NodeID, x, and y.

在步骤框架循环之前预处理节点数据,进行所有需要的转换(例如,转换为整数)。

重构可维护性。你有几个代码块基本上做同样的事情,有轻微的变化。从长远来看,很难维护这样的代码,因为你必须注意到类似语法令人头脑麻木的海洋中的微妙差异。考虑不同的数据结构,或考虑使用迭代来减少代码重复的方法。这些更改不一定会使您的代码运行得更快(并且可能使其运行速度稍慢),但是权衡通常是值得的,因为您将能够更有效地推理您的代码 - 从而发现真正的性能瓶颈是。

答案 1 :(得分:2)

您的算法似乎是:

O(nsteps * frames_in_step * values_in_frame * nodes)

如果您事先不了解任何元素的大小,那么总计为O(n^4)

正如罗伯特指出的那样,显然,每次迭代只使用一个节点。您可以使用dict nodeID: (x,y,z)。这将允许O(1)检索节点。通常,预处理是:

nodes_dict = { nodeID:(x,y,z) for nodeID, x, y, z in nodes }

然后在循环中,只需调用:

x, y, z = nodes_dict.get(int(v.nodeLabel))

这会将您的复杂程度降低到O(n^3)。我不认为算法可以进一步简化。

然后,您将访问多次相同的数组项。这很慢,所以你可以缓存它们。 v.data[x]在每次迭代中使用4到8次。您可以使用临时变量将其减少到仅为1。

修改

如我的评论所述,umax = max(v.data)表示所有数据索引。 给定u1max = max(v.values[0]所有值u2max = max(v.values[1]u3max = max(v.values[2],看来umax = max(u1max, u2max, u3max)

因此,您可以在处理完毕后将umax处理完成在所有循环之外,并简单地将其放入:

if abs(u1max) >umax: #maximum UX
    umax=abs(u1max)
    tu='U1'
    stepumax=stepu1max
    nodeumax=nodeu1max
    incumax=incu1max
if abs(u2max) >umax: #maximum UY
    umax=abs(u2max)
    tu='U2'
    stepumax=stepu2max
    nodeumax=nodeu2max
    incumax=incu2max
if abs(u3max) >umax: #maximum UZ
    umax=abs(u3max)
    tu='U3'
    stepumax=stepu3max
    nodeumax=nodeu3max 
    incumax=incu3max

同样适用于uFmax

答案 2 :(得分:1)

嗯,根据你的umax和u1max值,你至少可以通过组合标准1和2来节省一些计算。

if abs(v.data[0]) >uFmax:
    calcs
elif abs(v.data[0] > u1Fmax:
    calcs

您使用的是:内存:保存数据库吗?

答案 3 :(得分:1)

如果您使用的是Python 2,请尝试将range替换为xrange,按http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Use_xrange_instead_of_range

这不适用于Python 3.并且只有在循环大量迭代时才会有所作为。

答案 4 :(得分:1)

如果要从文件中提取此数据,请构建数据库或使用redis存储数据的有序集(key-tuple)。

然后只需使用查询(或在redis,zrank中)来检索最大值 - 您在此处看到的是"在列中找到最大值"功能,而数据库具有预先构建和优化的所有代码,以便您以最快的速度享受。