繁体   English   中英

如何使用多个嵌套的for循环加快python 2程序的速度

[英]How to speed up a python 2 program with multiple nested for-loops

这段代码有多个for循环,我读的列表每个都有999点。 我想将此迭代最多10,000次。 但是,即使仅迭代2次,也要花费近10分钟的时间。

即使我发布了这个特定的代码,我认为我的问题的答案可以帮助其他人更快地使用大量数据运行其代码。

您的任何建议都将受到赞赏。 非常感谢。

这段代码的作用:基本上,我从文本文件的列表中读取数组。 每个列表(例如x1,y1,z1 ...等)每个都有999个元素。 我基于其他元素(两个内部循环)对列表中的每个元素进行操作。 最终结果是一个全新的列表,我称之为x2。 然后,该代码应重复“ n次”操作(外部循环)。

我的问题是,我只能在执行很长时间之前重复执行一次此迭代。

import matplotlib.pyplot as plt
from astropy.table import Table
from astropy.io import ascii
import numpy as np
import argparse
import time
#for 200
start_time = time.time()

npoints=999
n1, mass1, x1, y1,z1,vx1,vy1,vz1,fx_list,fy_list,fz_list= [],[],[],[],[],[],[],[],[],[],[]
AngL_list=[]
Etot0_list=[]
G=1
dt=.01

with open('homo_sph_N1000_R3_v1.dat') as f:
     for row in f.readlines():  
        if not row.startswith("#"):
            spaces=row.split('   ')
            n1.append(float(spaces[0]))
            mass1.append(float(spaces[1]))
            x1.append(float(spaces[2]))
            y1.append(float(spaces[3]))
            z1.append(float(spaces[4]))
            vx1.append(float(spaces[5]))
            vy1.append(float(spaces[6]))
            vz1.append(float(spaces[7]))

for n in range(2):
#changes the particle on which the forces are acting
     for xn in range(0,npoints):
     #changes the forces from other particles acting on the particle
          for step in range(0,npoints):
          #Here we find the accelearation for every particle
               fx=((G*mass1[xn]*mass1[step+1]*((x1[step+1]**2.+y1[step+1]**2.+z1[step+1]**2.)-(x1[xn]**2.+y1[xn]**2.+z1[xn]**2.)))/  (  abs((x1[step+1]**2.+y1[step+1]**2.+z1[step+1]**2.)-(x1[xn]**2.+y1[xn]**2.+z1[xn]**2.))**2.+(.2)**2  )**(3./2.))

               fy=((G*mass1[xn]*mass1[step+1]*((x1[step+1]**2.+y1[step+1]**2.+z1[step+1]**2.)-(x1[xn]**2.+y1[xn]**2.+z1[xn]**2.)))/  (    abs((x1[step+1]**2.+y1[step+1]**2.+z1[step+1]**2.)-(x1[xn]**2.+y1[xn]**2.+z1[xn]**2.))**2+(.2)**2 )**(3./2.))

               fz=((G*mass1[xn]*mass1[step+1]*((x1[step+1]**2.+y1[step+1]**2.+z1[step+1]**2.)-(x1[xn]**2.+y1[xn]**2.+z1[xn]**2.)))/  (    abs((x1[step+1]**2.+y1[step+1]**2.+z1[step+1]**2.)-(x1[xn]**2.+y1[xn]**2.+z1[xn]**2.))**2+(.2)**2 )**(3./2.))

               #Then put store it in an array
               fx_list.append(fx)
               fy_list.append(fy)
               fz_list.append(fz)


          #Now, I need to split that array up by npoints, each particle has npoints forces acting on it. 
          fxx= np.array_split(fx_list,npoints)
          fyy= np.array_split(fy_list,npoints)
          fzz= np.array_split(fz_list,npoints)

          #since the force on a particle is the sum of all forces acting on it, I'm summing each variable in each array together. e.g. [1,2,3]=[6] 
          fxxx_list=[]
          fyyy_list=[]
          fzzz_list=[]
          for xn in range(0,npoints):
               fxxx= np.sum(fxx[xn])
               fyyy= np.sum(fyy[xn])
               fzzz= np.sum(fzz[xn]) 

               #and save that in array. Now I have the accelearation on each particle. 
               fxxx_list.append(fxxx)
               fyyy_list.append(fyyy)
               fzzz_list.append(fzzz) 

          #This is where i begin the integration

          vx2=[]
          vy2=[]
          vz2=[] 
          for xn in range(0,npoints):

               vx11=vx1[xn]+.5*(fxxx_list[xn]+fxxx_list[xn])*dt
               vy11=vy1[xn]+.5*(fyyy_list[xn]+fyyy_list[xn])*dt
               vz11=vz1[xn]+.5*(fzzz_list[xn]+fyyy_list[xn])*dt 

               vx2.append(vx11)
               vy2.append(vy11)
               vz2.append(vz11) 

          x2=[]
          y2=[]
          z2=[]
          for xn in range(0,npoints):
               x11=(x1[xn]+vx2[xn]*dt)+(.5*fxxx_list[xn]*(dt**2))
               y11=(y1[xn]+vy2[xn]*dt)+(.5*fyyy_list[xn]*(dt**2))
               z11=(z1[xn]+vz2[xn]*dt)+(.5*fzzz_list[xn]*(dt**2)) 

               x2.append(x11)
               y2.append(y11)
               z2.append(z11)

x1,y1,z1,vx1,vy1,vz1 = x2,y2,z2,vx2,vy2,vz2

print x2,y2 
plt.scatter(x2,y2)

print("--- %s seconds ---" % (time.time() - start_time))    

plt.show()

这只是一个小小的提速,但是代码似乎在做很多x**2 (x平方)。

在python3中,执行x**2的速度通常比x*x慢。 考虑一个简单的测试程序:

import time

iteration_count=99999999

# Do a lot of squaring with the ** operator
start1 = time.time()
sum = 0
for i in range( iteration_count ):
    sum += i ** 2
end1 = time.time()


# Do a lot of squaring with i * i
start2 = time.time()
sum = 0
for i in range( iteration_count ):
    sum += i * i
end2 = time.time()

print("x**2 => %f seconds" % (end1-start1))
print("x*x  => %f seconds" % (end2-start2))

这给了我结果:

$ python3 ./squared.py 
x**2 => 21.347830 seconds
x*x  => 8.983334 seconds

我做了很多次,变化不大。

问题中的代码正在进行大量计算以使fxfyfz (这似乎是相同的?这是否正确?)如果这些计算存在任何共同点,则应删除中间结果,仅进行计算一旦。

例如,代替:

fx=((G*mass1[xn]*mass1[step+1]*((x1[step+1]**2.+y1[step+1]**2.+z1[step+1]**2.) ...
fy=((G*mass1[xn]*mass1[step+1]*((x1[step+1]**2.+y1[step+1]**2.+z1[step+1]**2.) ...
fz=((G*mass1[xn]*mass1[step+1]*((x1[step+1]**2.+y1[step+1]**2.+z1[step+1]**2.) ...

第一部分应该只计算一次:

g_mass = G*mass1[xn]*mass1[step+1]
fx=((g_mass * ((x1[step+1]**2.+y1[step+1]**2.+z1[step+1]**2.) ...
fy=((g_mass * ((x1[step+1]**2.+y1[step+1]**2.+z1[step+1]**2.) ...
fz=((g_mass * ((x1[step+1]**2.+y1[step+1]**2.+z1[step+1]**2.) ...

同样,这些公式的任何部分都有相同的组成部分。

我认为,如果您将输入转换为numpy数组,对numpy数组进行操作,并将numpy数组预先分配为其所需的大小,而不是使用列表,则应该能够大幅度提高速度(也许是1000倍)并随身携带它们。

例如,仅以开始示例为例,您可以执行以下操作(尽管我不能保证它确实可以满足您的要求,但这只是指导)

with open('homo_sph_N1000_R3_v1.dat') as f:
    for row in f.readlines():  
        if not row.startswith("#"):
            spaces=row.split('   ')
            n1.append(float(spaces[0]))
            mass1.append(float(spaces[1]))
            x1.append(float(spaces[2]))
            y1.append(float(spaces[3]))
            z1.append(float(spaces[4]))
            vx1.append(float(spaces[5]))
            vy1.append(float(spaces[6]))
            vz1.append(float(spaces[7]))

# convert to numpy arrays
n1 = np.array(n1)
mass1 = np.array(mass1)
# KEEP DOING THIS FOR THE OTHER INPUTS

for n in range(2):
    # PREALLOCATE
    fx = np.zeros(npoints, npoints-1)
    fy = np.zeros(npoints, npoints-1)
    fz = np.zeros(npoints, npoints-1)

    #changes the particle on which the forces are acting
    for xn in range(0,npoints):
        #changes the forces from other particles acting on the particle

        # REMOVE THE INNER FOR LOOP AND JUST USE THE ARRAYS
        #for step in range(0,npoints):
        #Here we find the accelearation for every particle
        fx[xn] = ((G*mass1[xn]*mass1[1:]*((x1[1:]**2.+y1[1:]**2.+z1[1:]**2.)-(x1[xn]**2.+y1[xn]**2.+z1[xn]**2.)))/  (  abs((x1[1:]**2.+y1[1:]**2.+z1[1:]**2.)-(x1[xn]**2.+y1[xn]**2.+z1[xn]**2.))**2.+(.2)**2  )**(3./2.))

        fy[xn] = ((G*mass1[xn]*mass1[1:]*((x1[1:]**2.+y1[1:]**2.+z1[1:]**2.)-(x1[xn]**2.+y1[xn]**2.+z1[xn]**2.)))/  (    abs((x1[1:]**2.+y1[1:]**2.+z1[1:]**2.)-(x1[xn]**2.+y1[xn]**2.+z1[xn]**2.))**2+(.2)**2 )**(3./2.))

        fz[xn] = ((G*mass1[xn]*mass1[1:]*((x1[1:]**2.+y1[1:]**2.+z1[1:]**2.)-(x1[xn]**2.+y1[xn]**2.+z1[xn]**2.)))/  (    abs((x1[1:]**2.+y1[1:]**2.+z1[1:]**2.)-(x1[xn]**2.+y1[xn]**2.+z1[xn]**2.))**2+(.2)**2 )**(3./2.))

      #Now, I need to split that array up by npoints, each particle has npoints forces acting on it. 
      fxx= np.array_split(fx,npoints)
      fyy= np.array_split(fy,npoints)
      fzz= np.array_split(fz,npoints)

      #since the force on a particle is the sum of all forces acting on it, I'm summing each variable in each array together. e.g. [1,2,3]=[6] 
      fxxx= np.sum(fxx[xn], axis=1)
      fyyy= np.sum(fyy[xn], axis=1)
      fzzz= np.sum(fzz[xn], axis=1) 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM