我们有一批raw data 文件(二进制文件),需要把这批文件读入之后处理成正常数据,并经过几步操作后存成dict的形式,每个key对应一个一维numpy矩阵,然后把这个dict存成pkl文件。处理完之后,我们需要调用matplotlib来把pkl文件中某一个或某几个key对应的numpy矩阵画出来。
初始的做法是,我挨个读入raw data,处理成pkl文件;等所有的raw data都被处理完成之后,使用matplotlib把所有的pkl文件一个一个地画出来。对这个流程计时,发现读入数据并将其转换成可用数据用了600多秒;几步操作共用了300多秒;画图用了1300多秒。整个流程耗时接近40分钟。而这仅仅是很短的一部分数据。以后数据量如果大起来,这个处理速度显然是不行的。
于是并行操作成为了必然的选择。刚开始想得也比较简单,由于画图占用的时间过长,超过了读入和处理数据加起来的时间总和,因此可以考虑两个进程,一个用来读入和处理数据并将处理好的数据存为pkl,另一个用来画图。这样的操作需要画图进程时刻去检查数据处理进程有没有处理好一个新的raw data并生成新的pkl文件。
这个需求很容易想到应该使用队列。具体来说,数据处理进程每次处理好一个raw data文件并生成对应pkl文件之后,将这个pkl文件的路径推进一个队列q;画图进程不断检查这个队列q,如果q非空,就使用q.get()得到一个pkl文件的路径,然后载入这个pkl文件并画图;如果q空了,可能有两种情况,一种是画图进程画得比较快,在数据处理进程还未处理好一个新的文件的时候,画图进程已经把队列里所有的pkl文件都画完了;另一种是所有文件都已经被处理完了,应该结束了。为了区别这两种情况,我们需要设置一个终止条件,满足终止条件则退出程序,否则继续循环,等待数据处理进程给q推进新的pkl文件路径。
这个思路的部分伪代码如下:
import multiprocessing as mp
import os
from pathlib import Path
from time import time
import matplotlib.pyplot as plt
import numpy as np
import utils # 一个自己写的工具包
class Process:
def __init__(self, input_path, mid_path, plot_path):
self.input_path = Path(input_path) # raw data文件位置
self.mid_path = Path(mid_path) # 创建pkl文