cProfile
是 Python 中用于性能分析的内置模块,它可以帮助你确定程序中哪些部分消耗了最多的时间。通常,使用 cProfile
会输出大量的数据,需要进行解析和分析。下面是关于 cProfile
输出解析及其解决方案的一些提示:
1、问题背景
我们有一个 Python 脚本,它通过 CSV 文件进行顺序解析,并执行简单的数据清理,然后将数据写入一个新的 CSV 文件中。脚本运行非常慢。使用 cProfile 进行分析,得到了以下输出:
问题截图链接
2、解决方案
为了搞清楚为什么脚本运行这么慢,我们分析了 cProfile 的输出结果。我们发现问题在于 db_insert
函数,它负责将数据插入到数据库中。
def db_insert(coCode, bse):
start = time()
q = []
print os.path.join(FILE_PATH, str(bse)+"_clean.csv");
f1 = open(os.path.join(FILE_PATH, str(bse)+"_clean.csv"))
reader = csv.reader(f1)
reader.next()
end = time()
# print end-start
for idx,row in enumerate(reader):
ohlc = {}
date = datetime.strptime( row[0], '%Y-%m-%d')
date = row[0]
row = row[1:6]
(op, high, low, close, volume) = row
ohlc[date] = {}
ohlc[date]['open'] = op
ohlc[date]['high'] = high
ohlc[date]['low'] = low
ohlc[date]['close'] = close
ohlc[date]['volume'] = volume
q.append(ohlc)
end1 = time()
# print end1-end
db.quotes.insert({'bse':str(bse), 'quotes':q})
# print time()-end1
f1.close()
q = []
print os.path.join(FILE_PATH, str(coCode)+".csv");
f2 = open(os.path.join(FILE_PATH, str(bse)+"_clean.csv"))
reader = csv.reader(f2)
reader.next()
for idx,row in enumerate(reader):
ohlc = {}
date = datetime.strptime( row[0], '%Y-%m-%d')
date = row[0]
try:
extra = row[7]+row[8]+row[9]
except:
try:
extra = row[7]
except:
extra = ''
row = row[1:6]
(op, high, low, close, volume) = row
ohlc[date] = {}
ohlc[date]['open'] = op
ohlc[date]['high'] = high
ohlc[date]['low'] = low
ohlc[date]['close'] = close
ohlc[date]['volume'] = volume
ohlc[date]['extra'] = extra
q.append(ohlc)
db.quotes_unadjusted.insert({'bse':str(bse), 'quotes':q})
f2.close()
在 cProfile 的输出中,我们看到 db_insert
函数的 tottime
和 cumtime
都非常高,说明这个函数花费了很长时间。进一步分析发现,函数中有一个循环,每次迭代都会从文件中读取一行数据,然后将数据转换成一个字典,最后将字典添加到一个列表中。这个过程非常耗时,尤其是当文件很大时。
为了解决这个问题,我们可以对 db_insert
函数进行优化。一种方法是使用 Pandas 库来读取 CSV 文件,因为 Pandas 可以一次性将整个文件读入内存,然后进行快速的数据处理。另一种方法是使用多线程或多进程来并行处理数据,从而提高效率。
代码例子
import pandas as pd
def db_insert_optimized(coCode, bse):
# 使用 Pandas 读取 CSV 文件
df = pd.read_csv(os.path.join(FILE_PATH, str(bse)+"_clean.csv"))
# 将数据转换成字典
ohlc = df.to_dict('records')
# 将字典插入数据库
db.quotes.insert({'bse':str(bse), 'quotes':ohlc})
db.quotes_unadjusted.insert({'bse':str(bse), 'quotes':ohlc})
我们使用 Pandas 库来读取 CSV 文件,并将数据转换成一个字典,然后将字典插入到数据库中。这样可以大大提高脚本的运行速度。
总体来说,使用 cProfile
进行性能分析后,可以使用 pstats
模块提供的各种方法来解析和分析输出结果,从而找出程序中的性能瓶颈并进行优化。