Python的HtmlDiff.make_table()的最坏情况行为

时间:2011-08-10 15:27:12

标签: python diff time-complexity difflib

我正在使用Python 2.7的difflib.HtmlDiff.make_table()函数在内部测试用例运行器的预期文件和实际文件之间生成差异。它们最终出现在HTML测试报告中。

到目前为止这个工作正常 - 直到我添加了一个包含更大文件(~400 KiB)的测试用例,存在很多差异,通常不包含换行符。几乎所有的测试用例都在不到2秒的时间内完成,其中一些复杂的测试用例高达4秒。这个新的传球速度同样快,但需要13分钟(!)才能失败。所有这些时间都用于生成报告。我希望你能看出这是一个什么问题。

尝试证明这一点(可能不是最好的方式,我知道):

s = """import os, difflib
a = [os.urandom(length)]
b = [os.urandom(length)]
difflib.HtmlDiff().make_table(a, b)"""

import timeit
print 'length    100:', timeit.timeit(s, setup='length = 100', number=1)
print 'length   1000:', timeit.timeit(s, setup='length = 1000', number=1)
print 'length  10000:', timeit.timeit(s, setup='length = 10000', number=1)
print 'length 100000:', timeit.timeit(s, setup='length = 100000', number=1)
print 'length 400000:', timeit.timeit(s, setup='length = 400000', number=1)

结果:

length    100: 0.022672659081
length   1000: 0.0125987213238
length  10000: 0.479898318086
length 100000: 54.9947423284
length 400000: 1451.59828412

difflib.ndiff()(内部由make_table()使用,据我所知)似乎没有这个问题:

s = """import os, difflib
a = [os.urandom(length)]
b = [os.urandom(length)]
difflib.ndiff(a, b)"""

import timeit
print 'length    100:', timeit.timeit(s, setup='length = 100', number=100)
print 'length   1000:', timeit.timeit(s, setup='length = 1000', number=100)
print 'length  10000:', timeit.timeit(s, setup='length = 10000', number=100)
print 'length 100000:', timeit.timeit(s, setup='length = 100000', number=100)
print 'length 400000:', timeit.timeit(s, setup='length = 400000', number=100)

给我这个:

length    100: 0.0233492320197
length   1000: 0.00770079984919
length  10000: 0.0672924110913
length 100000: 0.480133018906
length 400000: 1.866792587

这看起来非常合理,即它是成比例的。四倍的大小需要四倍的时间。


不知道从哪里开始。我猜想,当存在差异时,HTML生成器会进行大量的回溯(尽管你会认为ndiff()已经处理过了)。我可以告诉它早点中止,放弃并将整个部分标记为“不同”吗?

据我所知,有许多不同的算法可用于生成差异。在这种情况下,我不需要它进行非常深入的分析并尝试在任何地方重新同步。我只是需要它来粗略地告诉我文件中的哪个位置不同,然后在合理的时间范围内终止。

或者,是否有其他生成HTML的Python差异库没有这种最坏的情况?

1 个答案:

答案 0 :(得分:0)

与此相关的CPython问题: