一、Python generator概述及大数据文件读取内存溢出分析
Generators是一类特殊的方法,这类方法返回一个lazy iterator而无需在内存中存储所有的数据内容。Generators是Python的核心内容,对于处理大数据量文件或者数据流(对于流式架构来说,通常有生产者和消费者,数据是一批一批或者一条一条进行处理的,在这种情况下,数据量可以是无限的,你无法预测会有多少数据)并同时需要进行更加精细的控制时是很有用的,在Rasa框架中可以看到基于generators架构的很多应用。
首先看下这种读取文件的方式:
在这个方法中,首先打开一个指定的文件,然后添加每一行数据作为一个元素放入到list中,如果你使用这种方式来统计一个文件中的行数,如果文件内容太大,那么就可能会看到下面的输出:
在这个例子中,方法open()返回一个generator object,正常情况下你可以使用懒加载机制来一行一行读取文件数据,然而如果你使用file.read().split()这种方式,那么就会一次性加载所有数据到内存中,在大数据量的情况下就容易造成MemoryError。
二、如何使用generator来解决大数据文件读取导致的内存溢出问题
在发生内存溢出错误之前,你可能已经发现计算机运行速度变慢了,所以如何处理大数据量的文件呢?下面这个例子改写了上面的方法:
在这个版本中,使用open打开一个文件,然后进行迭代操作,使用yield产出一行,最后可以看到使用这个代码做行数统计的输出效果如下:
上面这个例子就是把csv_reader()转换为一个generator方法,即打开文件后循环遍历每一行,然后产出每一行。使用yield会导致产生一个generator object。你也可以定义一个generator表达式,例如下面的例子,不需要定义一个方法:
你也可以使用generator来生成一个无限的数据序列,譬如下面这个方法:
通过循环调用这个方法来不断生成一个无限的数据序列,除非你主动停止运行它为止:
在这个例子中我们可以看到,在infinite_sequence()这个generator方法内部使用了yield,而yield是在内存中维护了generator的状态结构。如果你不使用for循环,那么也可以使用next()方法。
三、关于generator应用示例
下面开发了一段generator代码,演示如何使用generator逐行读取文件内容。这里使用了一个用于BERT模型训练的数据集CSV文件,文件前3行内容如下:
代码如下:
输出效果如下: