原创 深入 Python 解释器源码,我终于搞明白了字符串驻留的原理!

发布时间:2021-08-02 17:42:02 浏览 394 来源:猿笔记 作者:豌豆花下猫

    **字符串驻留是一种编译器/解释器的优化方法,这种优化方法不会每次都创建一个新的字符串副本“在某些语言中可能习惯用StringPool(字符串常量池)的概念”**字符串驻留提升了字符串比较的速度,即需要检查两个字符串中的每个字符,由于相同的字符串将使用同一个对象引用。**字符串驻留减少了内存占用。Python也使用字符串驻留来提高性能,字符串驻留是通过以下函数实现的,这个宏表明了Python在`PyASCIIObject`结构中维护着一个名为`interned`的成员变量。它的值表示相应的字符串是否被驻留?3##4、字符串驻留的原理。


    英文:

    作者:arpit

    译者:豆豆花猫(“Python猫”微信官方账号)

    声明:此翻译是为了交流和学习,基于CCBY-数控-SA4.0许可协议。为了方便阅读,内容略有改动。

    为了获得良好的性能,每种编程语言都需要大量的编译器级和解释器级优化。

    由于字符串是任何编程语言不可缺少的一部分,如果你有快速操作字符串的能力,就可以快速提高整体性能。

    在本文中,**我们将深入研究Python的内部实现,并了解Python如何使用一种名为字符串驻留([StringInterning](

    全文提纲如下:

    (回复**Python猫* *微信官方账号“0215”号,下载高清思维导图)

    ##1.什么是「弦常驻」?

    * *字符串常驻是编译器/解释器的一种优化方法,通过“缓存”一般字符串来节省字符串处理任务的空间和时间。**

    这种优化方法不会每次都创建一个新的字符串副本,而是只为每个*合适*不可变的值保留一个字符串副本,并使用指针来引用它。

    每个字符串的唯一拷贝被称为它的`intern`,并因此而得名StringInterning。

    Python Cat注意:StringInterning一般翻译为“字符串常驻”或“字符串保留”。在某些语言中,可能会用到StringPool的概念,这实际上是同一机制的不同表达。当实习生作为名词使用时,表示“实习生和实习生”,可以理解为“常驻和常驻价值”。

    查找字符串实习生的方法可能会也可能不会作为开放接口公开。现代编程语言,如Java、Python、PHP、Ruby、Julia等。,都支持字符串常驻,这样它们的编译器和解释器就可以达到很高的性能。

    ##2,为什么要驻留字符串?

    * *字符串驻留提高了字符串比较的速度。* *如果没有驻留,当我们要比较两个字符串是否相等时,其时间复杂度会上升到O(n),也就是需要检查两个字符串中的每个字符,才能判断是否相等。

    但是如果字符串是固定的,因为相同的字符串会使用相同的对象引用,仅仅检查指针是否相同就足以判断两个字符串是否相等,不需要逐个检查每个字符。因为这是一个非常常见的操作,所以它通常被实现为指针相等检查,只使用一条机器指令,根本没有内存引用。

    * *字符串驻留减少了内存使用。**Python通过“享受元设计模式”](

    ##3、Python的字符串驻留

    像大多数其他现代编程语言一样,Python使用字符串持久性来提高性能。在Python中,我们可以使用` is `运算符来检查两个对象是否引用同一个内存对象。

    因此,如果两个字符串对象引用同一个内存对象,“是”运算符将返回“真”,否则返回“假”。

    python>>>'python'is'python'True

    我们可以使用这个特殊的运算符来确定哪些字符串是驻留的。在CPython中,字符串驻留是通过以下函数实现的,这些函数在unicodeobject.h中声明,在unicode object.c中定义。

    cPyAPI_FUNC(void)PyUnicode_InternInPlace(PyObject**);

    为了检查一个字符串是否被驻留,CPython实现了一个名为`PyUnicode_CHECK_INTERNED`的宏,同样是定义在unicodeobject.h中。

    这个宏表示Python在PyASCIIObject结构中维护了一个名为interned的成员变量,它的值表示相应的字符串是否是常驻的。

    c#definePyUnicode_CHECK_INTERNED(op)\\(((PyASCIIObject*)(op))->state.interned)

    ##4、串住宅的原则

    * *在CPPython中,字符串的引用由名为“inter”的Python字典存储、访问和管理。* *字典在第一次调用常驻字符串时会延迟初始化,并保存对所有常驻字符串对象的引用。

    ###4.1如何驻留字符串?

    负责常驻字符串的核心函数是“py Unicode _ interninplace”,它是在unicodeobject.c中定义的,调用时,它将创建一个interned '准备容纳所有常驻字符串的字典,然后在参数中注册对象,以便它们的键和值都使用相同的对象引用。

    下面的函数片段展示了Python实现字符串驻留的过程。

    cvoidPyUnicode_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如何清理常驻字符串?

    清理函数遍历“插入”字典中的所有字符串,调整这些对象的引用计数,并将它们标记为“非插入”,以便对它们进行垃圾收集。一旦所有字符串都被标记为“非交错”,则“交错”字典将被清空和删除。

    这个清理函数就是`_PyUnicode_ClearInterned`,在[unicodeobject.c中](

    cvoid_PyUnicode_ClearInterned(PyThreadState*tstate){.........//GetallthekeystotheinterneddictionaryPyObject*keys=PyDict_Keys(interned);.........//InternedUnicodestringsarenotforciblydeallocated;//rather,wegivethemtheirstolenreferencesback//andthenclearandDECREFtheinterneddict.for(Py_ssize_ti=0;i

    ##5.字符串住宅的实现

    现在我们已经理解了字符串驻留和清理的内部原理,我们可以找出所有将驻留在Python中的字符串。

    为此,

作者信息

豌豆花下猫 [等级:3] python学习者@Python猫
发布了 148 篇专栏 · 获得点赞 614 · 获得阅读 108726

相关推荐 更多