Python 3.5与2.7文件读取及字符串拼接性能差异排查求助
问题分析与解决方案
首先咱们拆解下Python 2.7读取慢的核心原因:
- codecs模块在Python2中的效率瓶颈:Python2的
codecs.open返回的是UnicodeReader对象,它的UTF-8解码实现远不如Python3中经过优化的版本高效,处理大文件时,解码开销会被大幅放大。 - 一次性读取整个文件的内存压力:你的代码用
file_h.read()把34万行的文件全部加载到内存,生成一个超大的Unicode字符串。Python2对大字符串的处理(比如split("\n\n"))在内存管理和字符串操作效率上都比Python3逊色不少,这会进一步拖慢速度。
下面给你几个针对性的优化方案,按见效优先级排序:
方案1:改用io.open替代codecs.open
Python2.6及以上版本提供了io模块,它的open函数和Python3的open行为一致,底层的UTF-8解码实现更高效。修改代码如下:
import io # 替换原来的codecs导入 INPUT_DATA_DIR = 'some_tsv_file.tsv' ENT = "entities" def train_data_getter(input_dir=INPUT_DATA_DIR): with io.open(input_dir, encoding='utf-8') as file_h: data = file_h.read() sentences = data.split("\n\n") parsed_data = parser(sentences[0]) return parsed_data
这里顺便用了with语句,自动帮你关闭文件,比手动close()更安全。
方案2:避免一次性读取整个文件(最优)
注意到你的代码只处理sentences[0](第一个空行分隔的块),完全没必要读取整个文件。逐行读取并积累内容,遇到空行就停止处理,能大幅节省时间和内存:
import io def train_data_getter(input_dir=INPUT_DATA_DIR): current_sentence = [] parsed_data = None with io.open(input_dir, encoding='utf-8') as file_h: for line in file_h: line = line.rstrip("\n") if not line: # 遇到空行,处理当前句子 if current_sentence: sentence = "\n".join(current_sentence) parsed_data = parser(sentence) break # 拿到第一个块就直接跳出循环 else: current_sentence.append(line) # 处理文件末尾可能没有空行的情况 if not parsed_data and current_sentence: parsed_data = parser("\n".join(current_sentence)) return parsed_data
方案3:用内置open手动解码(备选)
如果因为环境限制不能用io模块,可以用Python2的内置open读取字节流,再手动解码成Unicode,速度也比codecs.open快:
def train_data_getter(input_dir=INPUT_DATA_DIR): with open(input_dir, 'rb') as file_h: data = file_h.read().decode('utf-8') sentences = data.split("\n\n") parsed_data = parser(sentences[0]) return parsed_data
内容的提问来源于stack exchange,提问作者ᴀʀᴍᴀɴ
相关产品推荐
相关产品推荐

