每一种编程语言都需要大量的编译器级和解释器级的优化,才能发挥出色,达到优异的性能。由于字符串是任何编程语言不可或缺的一部分,拥有快速操作字符串的能力可以快速提高整体性能。在本文中,我们将深入探讨Python的内部结构,了解Python如何使用一种称为字符串实习的技术来实现高解释器性能。这篇文章的目的不仅仅是介绍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和management的Python字典来存储和访问的。这个字典在第一次调用StringDwell时被延迟初始化,并保存对所有DwelledString对象的引用。4.1如何实习字符串?负责驻留字符串的核心函数是PyUnicode_InternInPlace,定义在unicodeobject.c中。调用时会创建一个准备容纳所有常驻字符串的interned字典,然后注册到参数Objects中,这样它们的键和值都使用同一个对象引用。以下函数片段显示了Python如何实现字符串持久化。voidPyUnicode_InternInPlace(PyObject**p){PyObject*s=*p;.......//LazilybuildthedictionarytoholdinternedStringsif(interned==NULL){interned=PyDict_New();if(interned==NULL){PyErr_Clear();return;}}PyObject*t;//Makeanentrytotheinterneddictionaryforthe//givenobjectt=PyDict_SetDefault(interned,s,s);......//Thetworeferencesininterneddict(keyandvalue)are//notcountedbyrefcnt.//unicode_dealloc()and_PyUnicode_ClearInterned()take//careofthis.Py_SET_REFCNT(s,Py_REFCNT(s)-2);//SetthestateofthestringtobeINTERNED_PyUnicode_STATE(s).interned=SSTATE_INTERNED_MORTAL;}4.2如何清理常驻字符串?,调整这些对象的引用计数,并将它们标记为NOT_INTERNED以进行垃圾回收。一旦所有字符串都标记为NOT_INTERNED,则interned字典将被清空并删除。这个清理函数是_PyUnicode_ClearInterned,定义在unicodeobject.c中。void_PyUnicode_ClearInterned(PyThreadState*tstate){.........//GetallthekeystotheinterneddictionaryPyObject*keys=PyDict_Keys(interned);......//InternedUnicodestrings未被强制释放;//相反,我们将它们被盗的引用返回//然后clearandDECREFtheinterneddict.for(Py_ssize_ti=0;i
