Python标准库Difflib有坑? —— 两个方法快速提升数据对比效率
admin
2023-07-07 13:44:12
0

一 前言

最近在开发的数据核对方案中用到了Python标准库Difflib,本来它工作的挺符合预期,可当它遇到那个文件,仿佛遇到了克星,那文件才100行*77列的数据,经它对比,居然耗时61s。这是无法接受的,因为后续线上流量抽取比对,绝非这点量级。该怎么破?

 

二 重现现象

以下是使用Difflib比对那个文件,数据量是100行*77列,耗时61s,如下:

Python标准库Difflib有坑? —— 两个方法快速提升数据对比效率

好吧,那就降低数据量到5行*77列,看看效果,耗时只有0.05s,如下:

Python标准库Difflib有坑? —— 两个方法快速提升数据对比效率


从耗时结果上,不难发现,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有坑? —— 两个方法快速提升数据对比效率

 

六 其他

本文针对Python标准库Difflib比对文件时遇到的耗时严重问题,提出了两种优化策略,并经测试验证有效,即仅在数据分片策略下,同样文件的比对耗时从原先的61s降到1.8s,且耗时只是线性增加。如果有更好的方法,欢迎留言、交流。

关于python学习、分享、交流,笔者开通了微信公众号【小蟒社区】,感兴趣的朋友可以关注下,欢迎加入,建立属于我们自己的小圈子,一起学python。


相关内容

热门资讯

我国科学家为细胞信号“导航”开... 新华社济南5月31日电(记者张力元)人体细胞犹如一座精密的通信城市,每天都有大量“指令”穿梭传递,调...
极端大风突袭哈尔滨!过山车停摆... 极目新闻记者 詹钘5月31日,受强对流天气影响,哈尔滨国际会展中心体育场相关设施受到损坏,原计划当晚...
三原电缆取得电缆接头连接用防护... 国家知识产权局信息显示,上海三原电缆附件有限公司取得一项名为“一种电缆接头连接用防护结构”的专利,授...
原创 识... 还是那句话,机圈苦大屏久已…… 虽然大屏有大屏的美,但是小屏也有小屏的俏。在大屏旗舰占据主流的手机市...
玄戒技术取得分频电路专利,实现... 国家知识产权局信息显示,北京玄戒技术有限公司取得一项名为“分频电路、分频器、射频芯片和电子设备”的专...
为什么今年香会基调明显变了 5月29日—31日在新加坡举行的第23届香格里拉对话会(简称“香会”),见证着元首引领下大国关系继续...
成本几毛钱、假驱蚊液香精兑水,... 入夏升温,蚊虫进入活跃期,驱蚊防护成为民生刚需,《财经调查》持续接到消费者投诉,他们买到的多款网红驱...
越来越多80后90后,正在丧失... 六一儿童节到来之际,朋友圈里开始出现一种熟悉的热闹。有人晒出零食礼包,有人半开玩笑地向伴侣讨礼物,还...
洋保电子取得用于低温环境的电气... 国家知识产权局信息显示,洋保电子(太仓)有限公司取得一项名为“一种用于低温环境的电气柜”的专利,授权...
中日韩飞手争霸宁波!2026无... 潮新闻客户端 记者 陈冲 通讯员 朱凝 5月31日,2026小遛·无人机竞速世界杯(中国·宁波鄞州站...