我有以下代码:
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。
有没有办法让这段代码更快?
答案 0 :(得分:3)
你说你有4个步骤,2000个帧和10000个节点。根据这些数字,这里有一些想法:
在节点循环之外移动计算。如果某个值不随节点变化,请在进入节点循环之前使用该值进行计算。
考虑节点的不同数据结构。对于所有8000个步骤帧,您将遍历整个节点列表。但是,您只关心满足基于nodeID
,x
和y
的两个条件测试的节点。如果您可以直接查找所需的节点,可能会更快。例如:
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中)来检索最大值 - 您在此处看到的是"在列中找到最大值"功能,而数据库具有预先构建和优化的所有代码,以便您以最快的速度享受。