英文:https://arpitbhayani.me/blogs...作者:arpit已在CCBY-NC-SA4.0下获得许可。为便于阅读,内容略有修改。每种编程语言都需要大量的编译器级别和解释器级别的优化才能表现良好并获得出色的性能。由于字符串是任何编程语言不可或缺的一部分,拥有快速操作字符串的能力可以快速提高整体性能。在本文中,我们将深入探讨Python的内部实现,并了解Python如何使用一种称为StringInterning的技术来实现高解释器性能。这篇文章的目的不仅仅是介绍Python的内幕,也是为了让读者能够轻松的浏览Python的源码;因此,本文中将有许多来自CPython的代码片段。全文提纲如下:(在Python猫公众号回复号码“0215”,下载高清思维导图)1、什么是“字符串驻留”?字符串持久化是一种编译器/解释器优化,它通过缓存通用字符串来节省字符串处理任务的空间和时间。这种优化不是每次都创建一个新的字符串副本,而是只为每个适当的不可变值保留一个字符串副本,并使用指针引用它。每个字符串的唯一副本称为它的实习生,因此得名字符串实习生。Python猫注:StringInterning一般翻译为“字符串驻留”或“字符串保留”。在某些语言中,可能会用到StringPool(字符串常量池)的概念,这实际上是同一个机制的不同机制。表达。当intern作为名词使用时,表示“实习生,实习生”,这里可以理解为“常驻对象,常驻值”。查找字符串实习生的方法可能会也可能不会公开为公共接口。Java、Python、PHP、Ruby、Julia等现代编程语言都支持字符串持久化,以使其编译器和解释器性能良好。2、字符串为什么要常驻?字符串持久性提高了字符串比较的速度。如果没有常驻,当我们要比较两个字符串是否相等时,其时间复杂度会上升到O(n),即需要检查两个字符串中的每个字符来判断是否相等。但是,如果字符串是固定的,由于同一个字符串会使用同一个对象引用,所以只要检查指针是否相同就可以判断两个字符串是否相等,不需要一个一个地检查每个字符.由于这是一个非常常见的操作,它通常被实现为指针相等性检查,只使用一条机器指令,根本没有内存引用。字符串持久化减少了内存占用。Python避免在内存中填充冗余的字符串对象,通过享受设计模式共享和重用定义的对象来优化内存使用。3.Python的字符串持久化与大多数其他现代编程语言一样,Python也使用字符串持久化来提高性能。在Python中,我们可以使用is运算符来检查两个对象是否引用同一个内存对象。因此,如果两个字符串对象引用同一个内存对象,则is运算符将返回True,否则返回False。>>>'python'is'python'True我们可以使用这个特定的运算符来确定哪些字符串是常驻的。在CPython中,字符串持久化由以下函数实现,在unicodeobject.h中声明并在unicodeobject.c中定义。PyAPI_FUNC(void)PyUnicode_InternInPlace(PyObject**);为了检查字符串是否常驻,CPython实现了一个名为PyUnicode_CHECK_INTERNED的宏,该宏也定义在unicodeobject.h中。该宏表示Python在PyASCIIObject结构中维护了一个名为interned的成员变量,其值表示对应的字符串是否常驻。#definePyUnicode_CHECK_INTERNED(op)\(((PyASCIIObject*)(op))->state.interned)4.字符串常驻原理在CPython中,字符串的引用由一个名为interned的Python字典存储,访问和管理.这个字典在第一次调用StringDwell时被延迟初始化,并保存对所有DwelledString对象的引用。4.1如何驻留字符串?负责驻留字符串的核心函数是PyUnicode_InternInPlace,定义在unicodeobject.c中。调用时会创建一个interned字典,准备容纳所有常驻字符串,然后在参数中注册对象,使其key和value都使用同一个对象引用。以下函数片段显示了Python如何实现字符串持久化。voidPyUnicode_InternInPlace(PyObject**p){PyObject*s=*p;.........//懒惰地构建字典来保存实习字符串if(interned==NULL){interned=PyDict_New();if(interned==NULL){PyErr_Clear();返回;}}PyObject*t;//为给定的对象在interned字典中创建一个条目t=PyDict_SetDefault(interned,s,s);......//interneddict中的两个引用(key和value)//不被refcnt计算在内。//unicode_dealloc()和_PyUnicode_ClearInterned()//处理这个。Py_SET_REFCNT(s,Py_REFCNT(s)-2);//设置字符串的状态为INTERNED_PyUnicode_STATE(s).interned=SSTATE_INTERNED_MORTAL;}4.2如何清理interned字符串?cleanup函数遍历interned字典中的所有字符串,调整这些对象的引用计数,并将它们标记为NOT_INTERNED以进行垃圾回收。一旦所有字符串都标记为NOT_INTERNED,则interned字典将被清空并删除。这个清理函数是_PyUnicode_ClearInterned,定义在unicodeobject.c中。void_PyUnicode_ClearInterned(PyThreadState*tstate){.........//获取interned字典的所有键PyObject*keys=PyDict_Keys(interned);.........//InternedUnicodestrings不会被强制释放;//相反,我们将他们被盗的引用还给他们//然后清除并删除interneddict。对于(Py_ssize_ti=0;i
