一 前言html
最近在开发的数据核对方案中用到了Python标准库Difflib,原本它工做的挺符合预期,可当它遇到那个文件,仿佛遇到了克星,那文件才100行*77列的数据,经它对比,竟然耗时61s。这是没法接受的,由于后续线上流量抽取比对,绝非这点量级。该怎么破?python
二 重现现象微信
如下是使用Difflib比对那个文件,数据量是100行*77列,耗时61s,以下:app
好吧,那就下降数据量到5行*77列,看看效果,耗时只有0.05s,以下:ide
从耗时结果上,不难发现,Difflib在这个文件的比对性能较差,并且耗时不随数据量线性增长,这是最恐怖的地方,若是继续增大数据量,耗时将会变得没法忍受。性能
三 优化思路学习
Difflib做为标准库,它的功能只是比对数据,而后生成各样结果格式。当遇到耗时严重这类问题,首先应该从本身的数据上入手,个人优化思路有两个:测试
第一, 过滤掉相同的行数据,下降比对数据量;大数据
第二, 数据分片;优化
针对第一个思路,将文件以行分割存放到列表,而后将列表相同位置的相同数据删除掉,只剩下不一样的行数据,这样作的好处很明显,一方面能够下降比对的数据量,提高效率,另外,输出的结果也更干净,不会再输出无必要的相同行数据;
针对第二个思路,将待比对的数据划分红一个个相对较小的数据块,实现快速比对,这个方法的可行性,能够从上述数据量耗时比对得出。
四 具体实现
过滤相同行优化策略,实现代码以下:
# 过滤相同行 source_length = len(source) # source为原始数据按行分割的列表 target_length = len(target) # target为目标数据按行分割的列表 min_length = source_length if source_length < target_length else target_length pos_list = [] # 标记相同行的行号,保留列头 for index in range(1, min_length): # 注意保序 if operator.eq(source[index], target[index]): pos_list.append(index) # 删除相同行数据, 注意索引漂移 source = [source[index] for index in range(source_length) if index not in pos_list] target = [target[index] for index in range(target_length) if index not in pos_list]
数据分片优化策略,实现代码以下:
# 分片 max_length = source_length if source_length > target_length else target_length # 用于分片 # 分片,注意保证不能漏行 start_pos = 0 step = 10 # 分片大小,即单次比对行数,默认10行 end_pos = start_pos + step diff = difflib.HtmlDiff() # 建立htmldiff实例对象 while end_pos < max_length + step: detail_info = diff.make_file(source[start_pos: end_pos], target[start_pos: end_pos]) # 处理逻辑
五 优化结果
在仅使用数据分片的优化策略的状况下,比对那个100行*77列的文件,结果显示比对耗时仅1.8s。而正如上文所述,优化前比对该文件的耗时为61s,更重要的是,由于数据分片,每片比对耗时基本稳定,即便数据量继续增大,耗时也只是线性增长,而再也不是相似指数型增长。另外,若是叠加过滤数据的第一种策略,相信随着数据量的降低,耗时数据会有更好的表现。但为了更直观的比对相同数据量下优化先后的效果,因此,在此只是使用数据分片的策略。
优化后耗时结果以下:
六 其余
本文针对Python标准库Difflib比对文件时遇到的耗时严重问题,提出了两种优化策略,并经测试验证有效,即仅在数据分片策略下,一样文件的比对耗时从原先的61s降到1.8s,且耗时只是线性增长。若是有更好的方法,欢迎留言、交流。
关于python学习、分享、交流,笔者开通了微信公众号【小蟒社区】,感兴趣的朋友能够关注下,欢迎加入,创建属于咱们本身的小圈子,一块儿学python。