通过一次GC调整使Python速度提高20%


Python有两种类型的内存管理:

  • 主要是引用计数。对象会跟踪指向它们的变量的数量。如果这个数字达到了0,它们就会被立即删除,而且是确定性的。在没有统计数据支持的情况下,我猜测99.9%以上的内存是这样处理的。
  • 0.1%:这里失败的一个案例是如果你有一个循环(想想有配偶字段的 Person 对象)。输入垃圾收集 .它偶尔会运行,寻找遗漏的参考计数清理。

引用计数很好,但GC,它运行得太频繁了。
触发因素是当你分配的700个或更多的容器对象(类、数据集、图元、列表等)超过已清理的数量时,会运行一个GC循环。
例如,当你做一个查询:
recent = await PageHits.objects().filter(date >= today).to_list()

如果该查询中有接近 700 个结果,那么您甚至在获得完整列表之前就已经达到了 GC 周期。
我们在Talk Python Training上的站点地图仅加载页面就产生了 77 个 GC 周期,77!
training.talkpython.fm/sitemap.xml

但你可以改变它。
在应用程序启动时尝试此代码:

# Clean up what might be garbage so far.
gc.collect(2)
# Exclude current items from future GC.
gc.freeze()

allocs, gen1, gen2 = gc.get_threshold()
allocs = 50_000  # Start the GC sequence every 50K not 700 allocations.
gen1 = gen1 * 2
gen2 = gen2 * 2
gc.set_threshold(allocs, gen1, gen2)

在 Talk Python 上,我们看到整体速度提高了 20%,而内存使用没有变化。

关于这种改进对于实际工作负载的现实性存在一些争论。
这篇文章引起了相当多的讨论。您可以在 Mastodon 线程上看到它。