多线程IO
首先说明一下,在以上优化手段之后,又在代码层面做了进一步的优化,原先单线程的脚本的计算性能进一步得到极大的提升
从上图可以看到,在整体的耗时中,excel保存的耗时是最多的(12.3s),其次是excel的读取(7.04s),最后才是内存计算(3.83s)。
之前说到性能优化的二八准则,也即通过数据分析发现瓶颈,即占用80%耗时的地方,然后有针对性地优化该瓶颈。可以看到我们这个脚本的性能瓶颈主要在文件IO上,也即这是一个IO密集型的场景。因此,优化目标要聚集在两个IO环节上,即excel的读取和写入。
从性能数据上看,首先要优化的应该是excel的写入,但很遗憾的是,我们的excel是写入一个而不是多个文件,而且是写入文件的同一个sheet,所以没法通过并发的方式进行优化。
所以,优化目标只能转而求其次聚焦在excel的读取上。因为读取的是excel的两个不同的sheet,所以可以考虑采取并发读取的方式来进行优化。而根据之前对Python多线程、多进程和协程的介绍,要优化的场景属于IO密集型场景,所以考虑用多线程或协程的方案进行优化。先来看一下用多线程来优化,代码如下:
#要处理的文件路径
fpath = "datas/joyce/DS_format_bak.xlsm"
def t_read_cp_df():
read_cp_df_start = time.time()
global cp_df
cp_df = pd.read_excel(fpath,sheet_name="CP",header=[0])
read_cp_df_end = time.time()
print(f"{threading.current_thread().getName()}读取excel文件cp sheet time cost is :{read_cp_df_end - read_cp_df_start} seconds")
def t_read_ds_df():
t_read_ds_df_start = time.time()
global ds_df
ds_df = pd.read_excel(fpath,sheet_name="DS",header=[0,1])
t_read_ds_df_end = time.time()
print(f"{threading.current_thread().getName()}读取excel文件ds sheet time cost is :{t_read_ds_df_end - t_read_ds_df_start} seconds")
def read_excel():
read_excel_start = time.time()
#把CP和DS两个sheet的数据分别读入pandas的dataframe
#启动两个线程并行读取excel的数据
read_cp_df_thread = Thread(target=t_read_cp_df,args=())
read_cp_df_thread.start()
read_ds_df_thread = Thread(target=t_read_ds_df,args=())
read_ds_df_thread.start()
read_cp_df_thread.join()
read_ds_df_thread.join()
read_excel_end = time.time()
print(f"读取excel文件 time cost is :{read_excel_end - read_excel_start} seconds")
从上图可以看出,读取excel的耗时减少到了5.1s,而且分别细看一下两个线程的读取excel时间,整体的excel读取时间是小于两个线程分别读取excel的时间之和的,说明两个线程对excel文件的读取性能是优于单线程串行读取的。