大规模Python:严格的模块

2020-12-18 16:07:27

欢迎来到Instagram上有关Python系列的第三篇文章!正如我们在本系列的第一篇文章中提到的那样,Instagram服务器是数百万行的Python整体,并且移动迅速:每天数百次提交,每隔几分钟部署到生产中。

以这种规模和速度使用Python时,我们遇到了一些痛点。本文介绍了一些我们认为可能也会影响其他方面的内容。考虑以下无害的示例模块:

从mywebframework import db导入re,路由VALID_NAME_RE = re.compile(" ^ [a-zA-Z0-9] + $")@route(' /')def home ():返回" Hello World!"类Person(db.Model):名称:str

我们将运行一堆正则表达式代码,以将该字符串编译为模式对象。

我们将运行@route装饰器。根据我们在此处看到的内容,我们可以假定它可能是在某些url映射中注册了该视图。这意味着仅通过导入此模块,我们就可以在其他地方更改全局状态。

我们将在Person类的主体内运行所有代码,其中可以包括任意代码。并且Model基类可能具有一个元类或__init_subclass__方法,这仍然是我们在导入时可能正在运行的任意代码。

此模块中唯一(可能)不会在导入时运行的代码行是return" Hello World!&#34 ;,但我们甚至不能肯定地说!因此,仅通过导入这个简单的八行模块(甚至还没有做任何事情!),我们可能正在运行数百行(如果不是数千行)Python代码,更不用说在程序其他地方修改全局URL映射了。所以呢?这是Python成为动态的解释语言的部分含义。这使我们能够进行各种有用的元编程。这有什么问题?当您使用相对较小的代码库和团队时,这没什么不对的,并且您可以保证在使用这些功能方面有一定的纪律性。但是,当您有成百上千的开发人员正在处理数百万行代码时,这种动态性的某些方面可能会引起关注,其中许多开发人员是Python的新手。例如,关于Python的一大优点是您可以快速迭代它:进行更改并查看结果,无需编译!但是随着几百万行代码(和混乱的依赖图)的出现,这种优势开始变糟。我们的服务器启动需要20多个时间,如果我们不注意使其保持最佳状态,则有时会缩短到一分钟左右。这意味着开发人员进行更改与能够在其浏览器甚至是单元测试中看到更改结果之间的间隔为20-60秒。不幸的是,这是完美的时光,让您分心于闪亮的事物而忘记了自己在做什么。大部分时间实际上只是用于导入模块,创建函数和类对象。在某些方面,这与等待另一种语言编译没有什么不同。但是通常编译可以是渐进式的:您可以重新编译更改的内容以及直接依赖于此的内容,因此许多较小的更改可以快速编译。但是在Python中,由于导入会产生任意副作用,因此没有安全的方法来增量地重新加载服务器。无论更改有多小,我们每次都必须从头开始,导入所有这些模块,重新创建所有这些类和函数,重新编译所有这些正则表达式,等等。通常99%的代码都没有; t自上次重新加载服务器以来已发生变化,但无论如何我们都必须重新做所有缓慢的工作。除了减慢开发​​人员的速度外,这也是生产中大量的计算浪费,因为我们不断地进行部署,因此整天不断地在生产服务器上重新加载站点。因此,这是我们的第一个痛苦点:由于导入时大量重复工作的浪费,导致服务器启动和重新加载速度缓慢。

Warning: Can only detect less than 5000 characters

创建后,其中定义的严格模块和类是不变的。通过将模块主体内部转换为一个函数,并将所有全局变量作为闭合变量进行访问,可以使模块不可变。尽管通过模块级可变容器选择加入,可变的全局状态仍然可用,但是这些更改极大地减少了全局状态意外突变的表面积。在严格模块中定义的类还必须在__init__中定义所有成员,并且模块加载器的AST转换会自动为其提供__slots__,因此以后无法添加其他临时实例属性。因此,例如,在此类中:

严格模块AST转换将在__init__中观察对属性名称和年龄的分配,并向该类添加隐式__slots__ =(' name&#39 ;,' age'),以防止分配任何类实例的其他属性。 (如果您使用类型注释,我们还将选择类级别的属性类型声明,例如name:str,并将它们也添加到插槽列表中。)这些限制不仅使代码更可靠,而且对它们有帮助跑得更快。自动转换类以添加__slots__使它们更有效地利用内存,并消除了按实例的字典查找,从而加快了属性访问的速度。转换模块主体使其不可变,也消除了用于访问顶级变量的字典查找。而且我们可以在Python运行时中进一步优化这些模式以获得更多好处。

严格的模块仍处于试验阶段。我们拥有一个可运行的原型,并且处于将其投入生产的初期阶段。我们希望将来能在此博客文章中继续介绍我们的经验,并详细介绍实施情况。如果您遇到类似的问题并对这种方法有想法,我们很乐意听到他们的声音!

非常感谢Dino Viehland和Shiyu Wang,他们实施了严格的模块并为这篇文章做出了贡献。如果您想了解更多有关这项工作的信息或有兴趣加入我们的工程团队之一,请访问我们的职业页面,在Facebook或Twitter上关注我们。