如何使代码运行更快?

159 阅读4分钟

要让代码运行得更快,可以从多个方面进行优化,包括算法、数据结构、并行化、I/O 操作等。以下是优化代码运行速度的主要方法:

a6.png

1、问题背景

下列为原始代码,使用 Python 从一个包含 6 列(0-5)的输入文件中读取数据,并进行一系列处理和计算,包括:

def check(inputfile):
  f = open(inputfile,'r') #reads the inputfile
  lines = f.readlines()
  for line in lines:
      job = line.split()
      if( int(job[0]) < history_ends ): #if the column0 is less then history_ends(i,e 5000 initially)
            historyjobs.append(job)
      else:
            targetjobs.append(job) 

2、解决方案

减少文件读取操作:

check 函数中,使用了 readlines() 方法读取整个文件,然后遍历每一行进行处理。但这是一种非常低效的做法,因为它需要将整个文件加载到内存中,然后再进行处理。

因此,为了提高效率,我们可以改为使用 for line in f: 来逐行读取文件。这样,就可以避免将整个文件加载到内存中,从而减少内存消耗并提高处理速度。

优化列表处理操作:

check 函数中,使用了 append 方法将每一行数据添加到 historyjobs 或 targetjobs 列表中。这是一种非常低效的做法,因为它需要对列表进行多次操作。

因此,为了提高效率,我们可以改为使用 extend 方法将每一行数据添加到 historyjobs 或 targetjobs 列表中。这样,就可以将多次操作合并为一次操作,从而减少时间复杂度并提高处理速度。

使用生成器表达式代替列表解析:

newfun 函数中,使用了列表解析来生成一个新的列表。这是一种非常低效的做法,因为它需要创建两个临时列表。

因此,为了提高效率,我们可以改为使用生成器表达式来生成一个新的列表。这样,就可以避免创建临时列表,从而减少内存消耗并提高处理速度。

使用 NumPy 库进行计算:

NumPy 是一个用于科学计算的 Python 库,它提供了许多高效的数值计算函数。

因此,我们可以使用 NumPy 库来代替一些内置的 Python 函数进行计算。例如,我们可以使用 numpy.mean() 函数来代替 sum() 函数计算列表的平均值,这可以提高计算速度。

使用多进程或多线程进行并行处理:

如果代码需要处理大量的数据,可以使用多进程或多线程进行并行处理。这可以充分利用计算机的多个核,从而提高处理速度。

代码示例:

import numpy as np
from multiprocessing import Pool
​
def check(inputfile):
  with open(inputfile, 'r') as f:
    for line in f:
      job = line.split()
      if int(job[0]) < history_ends:
        historyjobs.extend(job)
      else:
        targetjobs.extend(job)
​
def newfun(results):
  results = reversed(results)
  for value, average in results:
    a.append(value)
  return a
​
def runcheck(subseq):
  with open('newfileinput', 'r') as f:
    for line in f:
      job = line.split()
      for i, element in enumerate(subseq):
        if int(job[1]) == int(subseq[i]):
          condrun.append(job[2])
  return condrun
​
def listcreate(condrun, condsub):
  with open('outputfile', 'a') as f1:
    s = map(int, condrun)
    j = int(targetjobs[0][2])
    targetsub = int(targetjobs[0][1])
    if condsub != []:
      try:
        convertsub = int(condsub[-1])
        a=np.mean(s)
        c=max(s)
        d=min(s)
        e1=abs(j-a)
        er1=e1/j
        g=len(s)
        h=abs(convertsub-targetsub)
        f1.write(str(j))
        f1.write('\t')
        f1.write('\t')
        f1.write(str(round(a,2)))
        f1.write('\t')
        f1.write('\t')
        f1.write(str(round(er1,3)))
        f1.write('\t')
        f1.write('\t')
        f1.write(str(c))
        f1.write('\t')
        f1.write('\t')
        f1.write(str(d))
        f1.write('\t')
        f1.write('\t')
        f1.write(str(g))
        f1.write('\t')
        f1.write('\t')
        f1.write(str(h))
        f1.write('\t')
        f1.write("\t")
        if (float(er1) < 0.20):
          f1.write("good")
          f1.write("\t")
        else :
          f1.write("bad")
          f1.write("\t")
        if (float(er1) < 0.30):
          f1.write("good")
          f1.write("\t")
        else :
          f1.write("bad")
          f1.write("\t")
        if (float(er1) < 0.40):
          f1.write("good")
          f1.write("\t")
        else :
          f1.write("bad")
          f1.write("\t")
        if (float(er1) < 0.50):
          f1.write("good")
          f1.write("\n")
        else :
          f1.write("bad")
          f1.write("\n")
      except ZeroDivisionError :
        print 'dem 0'
    else:
      print '0'
      f1.close()
​
def new():
  global history_ends
  while 1:
    check('newfileinput')
    if len(targetjobs) != 1:
      history_ends = int(targetjobs[1][0])
      mlistsub = map(int,listsub)
      results = list(itertools.takewhile(lambda x: x[0] > 0.9 * x[1],
                    itertools.izip(reversed(mlistsub),
                    runningMean(reversed(mlistsub)))))
      condsub = newfun(results)
      condrun=runcheck(condsub)
      listcreate(condrun,condsub)
      del condrun[0:len(condrun)]
      del condsub[0:len(condsub)]
      del listsub[0:len(listsub)]
      del targetjobs[0:len(targetjobs)]
      del historyjobs[0:len(historyjobs)]
    else:
      break
​
def main():
  new()
​
if __name__ == '__main__':
  main()

使用多进程或多线程进行并行处理:

如果代码需要处理大量的数据,可以使用多进程或多线程进行并行处理。这可以充分利用计算机的多个核,从而提高处理速度。

例如,我们可以使用 multiprocessing 库来创建多个进程,并使用 Pool 类来管理这些进程。这样,就可以将任务分配给不同的进程来执行,从而提高处理速度。

def new():
  global history_ends
  while 1:
    with Pool(4) as p:
      p.map(check, ['newfileinput'])
​
    if len(targetjobs) != 1:
      history_ends = int(targetjobs[1][0])
      mlistsub = map(int,listsub)
      results = list(itertools.takewhile(lambda x: x[0] > 0.9 * x[1],
                    itertools.izip(reversed(mlistsub),
                    runningMean(reversed(mlistsub)))))
      condsub = newfun(results)
      condrun=runcheck(condsub)
      listcreate(condrun,condsub)
      del condrun[0:len(condrun)]
      del condsub[0:len(condsub)]
      del listsub[0:len(listsub)]
      del targetjobs[0:len(targetjobs)]
      del historyjobs[0:len(historyjobs)]
    else:
      break

通过以上优化,代码的运行速度可以得到显著提升。

总结

  • 优化代码运行速度的首要任务是找到瓶颈,通过分析工具(如 cProfile)定位性能热点。
  • 优先从算法和数据结构优化入手,其次是并行化、I/O 和硬件加速。
  • 对于高性能需求,可以使用专用库(如 NumPy、Pandas)或工具(如 Cython、Numba)。

通过这些方法,几乎所有类型的代码都可以实现显著的性能提升。