如何使python代码运行得更快
我正在编写在多个netcdf文件(大~28G)上循环的代码。netcdf文件在整个域中具有多个4D变量[时间、东西、南北、高度]。目标是在这些文件上循环,在域中所有这些变量的每个位置上循环,并将某些变量存储到一个大数组中。当文件丢失或不完整时,我用99.99填充值。现在,我只是通过每天循环2个netcdf文件进行测试,但由于某些原因,这需要花费很长时间(约14小时)。我不确定是否有办法优化这段代码。我认为python不应该花这么长时间来完成这项任务,但这可能是python或我的代码的问题。下面是我的代码,希望它是可读的,任何关于如何使其更快的建议都非常感谢:如何使python代码运行得更快,python,performance,loops,timing,Python,Performance,Loops,Timing,我正在编写在多个netcdf文件(大~28G)上循环的代码。netcdf文件在整个域中具有多个4D变量[时间、东西、南北、高度]。目标是在这些文件上循环,在域中所有这些变量的每个位置上循环,并将某些变量存储到一个大数组中。当文件丢失或不完整时,我用99.99填充值。现在,我只是通过每天循环2个netcdf文件进行测试,但由于某些原因,这需要花费很长时间(约14小时)。我不确定是否有办法优化这段代码。我认为python不应该花这么长时间来完成这项任务,但这可能是python或我的代码的问题。下面是
#Domain to loop over
k_space = np.arange(0,37)
j_space = np.arange(80,170)
i_space = np.arange(200,307)
predictors_wrf=[]
names_wrf=[]
counter = 0
cdate = start_date
while cdate <= end_date:
if cdate.month not in month_keep:
cdate+=inc
continue
yy = cdate.strftime('%Y')
mm = cdate.strftime('%m')
dd = cdate.strftime('%d')
filename = wrf_path+'\wrfoutRED_d01_'+yy+'-'+mm+'-'+dd+'_'+hour_str+'_00_00'
for i in i_space:
for j in j_space:
for k in k_space:
if os.path.isfile(filename):
f = nc.Dataset(filename,'r')
times = f.variables['Times'][1:]
num_lines = times.shape[0]
if num_lines == 144:
u = f.variables['U'][1:,k,j,i]
v = f.variables['V'][1:,k,j,i]
wspd = np.sqrt(u**2.+v**2.)
w = f.variables['W'][1:,k,j,i]
p = f.variables['P'][1:,k,j,i]
t = f.variables['T'][1:,k,j,i]
if num_lines < 144:
print "partial files for WRF: "+ filename
u = np.ones((144,))*99.99
v = np.ones((144,))*99.99
wspd = np.ones((144,))*99.99
w = np.ones((144,))*99.99
p = np.ones((144,))*99.99
t = np.ones((144,))*99.99
else:
u = np.ones((144,))*99.99
v = np.ones((144,))*99.99
wspd = np.ones((144,))*99.99
w = np.ones((144,))*99.99
p = np.ones((144,))*99.99
t = np.ones((144,))*99.99
counter=counter+1
predictors_wrf.append(u)
predictors_wrf.append(v)
predictors_wrf.append(wspd)
predictors_wrf.append(w)
predictors_wrf.append(p)
predictors_wrf.append(t)
u_names = 'u_'+str(k)+'_'+str(j)+'_'+str(i)
v_names = 'v_'+str(k)+'_'+str(j)+'_'+str(i)
wspd_names = 'wspd_'+str(k)+'_'+str(j)+'_'+str(i)
w_names = 'w_'+str(k)+'_'+str(j)+'_'+str(i)
p_names = 'p_'+str(k)+'_'+str(j)+'_'+str(i)
t_names = 't_'+str(k)+'_'+str(j)+'_'+str(i)
names_wrf.append(u_names)
names_wrf.append(v_names)
names_wrf.append(wspd_names)
names_wrf.append(w_names)
names_wrf.append(p_names)
names_wrf.append(t_names)
cdate+=inc
#要循环的域
k_空间=np.arange(0,37)
j_空间=np.arange(80170)
i_space=np.arange(200307)
预测因子_wrf=[]
名称\u wrf=[]
计数器=0
cdate=开始日期
虽然cdate我没有太多建议,但有几点需要注意
不要多次打开该文件
首先,定义这个filename
变量,然后在这个循环中(深层:三个循环表示深层),检查文件是否存在,并假定在那里打开它(我不知道nc.Dataset
做什么,但我猜它必须打开文件并读取):
这将是非常低效的。如果文件在所有循环之前没有更改,您当然可以打开它一次
尽量少用for循环
所有这些嵌套for循环都增加了需要执行的操作的数量。一般建议:尝试使用numpy操作
使用CProfile
如果你想知道为什么你的程序要花很长时间,最好的方法之一就是分析它们 这是收紧forloop
s的第一次尝试。由于每个文件只使用一次文件形状,因此可以将处理移到循环之外,这将减少中断处理时的数据加载量。我仍然不知道计数器
和inc
做什么,因为它们似乎在循环中没有更新。您肯定希望研究重复字符串连接性能,或者将附加到预测器和名称的性能作为起点
k_space = np.arange(0,37)
j_space = np.arange(80,170)
i_space = np.arange(200,307)
predictors_wrf=[]
names_wrf=[]
counter = 0
cdate = start_date
while cdate <= end_date:
if cdate.month not in month_keep:
cdate+=inc
continue
yy = cdate.strftime('%Y')
mm = cdate.strftime('%m')
dd = cdate.strftime('%d')
filename = wrf_path+'\wrfoutRED_d01_'+yy+'-'+mm+'-'+dd+'_'+hour_str+'_00_00'
file_exists = os.path.isfile(filename)
if file_exists:
f = nc.Dataset(filename,'r')
times = f.variables['Times'][1:]
num_lines = times.shape[0]
for i in i_space:
for j in j_space:
for k in k_space:
if file_exists:
if num_lines == 144:
u = f.variables['U'][1:,k,j,i]
v = f.variables['V'][1:,k,j,i]
wspd = np.sqrt(u**2.+v**2.)
w = f.variables['W'][1:,k,j,i]
p = f.variables['P'][1:,k,j,i]
t = f.variables['T'][1:,k,j,i]
if num_lines < 144:
print "partial files for WRF: "+ filename
u = np.ones((144,))*99.99
v = np.ones((144,))*99.99
wspd = np.ones((144,))*99.99
w = np.ones((144,))*99.99
p = np.ones((144,))*99.99
t = np.ones((144,))*99.99
else:
u = np.ones((144,))*99.99
v = np.ones((144,))*99.99
wspd = np.ones((144,))*99.99
w = np.ones((144,))*99.99
p = np.ones((144,))*99.99
t = np.ones((144,))*99.99
counter=counter+1
predictors_wrf.append(u)
predictors_wrf.append(v)
predictors_wrf.append(wspd)
predictors_wrf.append(w)
predictors_wrf.append(p)
predictors_wrf.append(t)
u_names = 'u_'+str(k)+'_'+str(j)+'_'+str(i)
v_names = 'v_'+str(k)+'_'+str(j)+'_'+str(i)
wspd_names = 'wspd_'+str(k)+'_'+str(j)+'_'+str(i)
w_names = 'w_'+str(k)+'_'+str(j)+'_'+str(i)
p_names = 'p_'+str(k)+'_'+str(j)+'_'+str(i)
t_names = 't_'+str(k)+'_'+str(j)+'_'+str(i)
names_wrf.append(u_names)
names_wrf.append(v_names)
names_wrf.append(wspd_names)
names_wrf.append(w_names)
names_wrf.append(p_names)
names_wrf.append(t_names)
cdate+=inc
k_空间=np.arange(0,37)
j_空间=np.arange(80170)
i_space=np.arange(200307)
预测因子_wrf=[]
名称\u wrf=[]
计数器=0
cdate=开始日期
虽然cdate对于你的问题,我认为会有很大帮助。我查阅了你的密码,这里有一些建议
不使用开始时间,而是使用文件名作为代码中的迭代器
包装一个函数,根据时间找出所有文件名,并返回所有文件名的列表
def fileNames(start_date, end_date):
# Find all filenames.
cdate = start_date
fileNameList = []
while cdate <= end_date:
if cdate.month not in month_keep:
cdate+=inc
continue
yy = cdate.strftime('%Y')
mm = cdate.strftime('%m')
dd = cdate.strftime('%d')
filename = wrf_path+'\wrfoutRED_d01_'+yy+'-'+mm+'-'+dd+'_'+hour_str+'_00_00'
fileNameList.append(filename)
cdate+=inc
return fileNameList
最后,注意这里的数据结构,因为它相当复杂。希望这有帮助。如果您还有任何问题,请留下评论
可以使用多处理同时处理文件。为不同的进程安排k、j、i空间,并让它们各自执行自己的任务什么是nc.Dataset
?另外,在你提高速度之前,你需要知道它为什么慢。您需要对代码进行评测和度量。这是我使用python读取netcdf文件的方式。我在代码前面有一句话没有在这里显示:将netCDF4导入为NCD。下面的多核建议会有所帮助。此外,如果您在iPython笔记本中工作,将其写入从命令行运行的脚本可以大大加快速度。28GB是一个巨大的文件。如果两个文件都在这个大小范围内,并且有3个循环,那么在一个内核上运行14个小时并不是不可能的,不管它看起来有多可笑。R比Python慢得多,更小的文件需要8-12个时间来排序,循环更少。对于冗余操作,请尽可能保守,并激发更多内核!您似乎多次遍历该文件,{f.variables['times'][1:]}遍历该文件以搜索这些变量。这是为每个循环完成的。这样做一次,而不是每次循环。
def fileNames(start_date, end_date):
# Find all filenames.
cdate = start_date
fileNameList = []
while cdate <= end_date:
if cdate.month not in month_keep:
cdate+=inc
continue
yy = cdate.strftime('%Y')
mm = cdate.strftime('%m')
dd = cdate.strftime('%d')
filename = wrf_path+'\wrfoutRED_d01_'+yy+'-'+mm+'-'+dd+'_'+hour_str+'_00_00'
fileNameList.append(filename)
cdate+=inc
return fileNameList
def dataExtraction(filename):
file_exists = os.path.isfile(filename)
if file_exists:
f = nc.Dataset(filename,'r')
times = f.variables['Times'][1:]
num_lines = times.shape[0]
for i in i_space:
for j in j_space:
for k in k_space:
if file_exists:
if num_lines == 144:
u = f.variables['U'][1:,k,j,i]
v = f.variables['V'][1:,k,j,i]
wspd = np.sqrt(u**2.+v**2.)
w = f.variables['W'][1:,k,j,i]
p = f.variables['P'][1:,k,j,i]
t = f.variables['T'][1:,k,j,i]
if num_lines < 144:
print "partial files for WRF: "+ filename
u = np.ones((144,))*99.99
v = np.ones((144,))*99.99
wspd = np.ones((144,))*99.99
w = np.ones((144,))*99.99
p = np.ones((144,))*99.99
t = np.ones((144,))*99.99
else:
u = np.ones((144,))*99.99
v = np.ones((144,))*99.99
wspd = np.ones((144,))*99.99
w = np.ones((144,))*99.99
p = np.ones((144,))*99.99
t = np.ones((144,))*99.99
counter=counter+1
predictors_wrf.append(u)
predictors_wrf.append(v)
predictors_wrf.append(wspd)
predictors_wrf.append(w)
predictors_wrf.append(p)
predictors_wrf.append(t)
u_names = 'u_'+str(k)+'_'+str(j)+'_'+str(i)
v_names = 'v_'+str(k)+'_'+str(j)+'_'+str(i)
wspd_names = 'wspd_'+str(k)+'_'+str(j)+'_'+str(i)
w_names = 'w_'+str(k)+'_'+str(j)+'_'+str(i)
p_names = 'p_'+str(k)+'_'+str(j)+'_'+str(i)
t_names = 't_'+str(k)+'_'+str(j)+'_'+str(i)
names_wrf.append(u_names)
names_wrf.append(v_names)
names_wrf.append(wspd_names)
names_wrf.append(w_names)
names_wrf.append(p_names)
names_wrf.append(t_names)
return zip(predictors_wrf, names_wrf)
if __name__ == '__main__':
from multiprocessing import Pool # This should be in the beginning statements.
start_date = '01-01-2017'
end_date = '01-15-2017'
fileNames = fileNames(start_date, end_date)
p = Pool(4) # the cores numbers you want to use.
results = p.map(dataExtraction, fileNames)
p.close()
p.join()