当前位置: 首页 > 后端技术 > Python

为了提高性能,Python居然利用了共享经济

时间:2023-03-26 12:33:29 Python

现在各行各业都掀起了一股python学习的热潮,几乎每个专业人士都在学习和使用python。python大家都不陌生,共享经济大家都知道,但是你了解python利用共享经济吗?想知道就看看今天给大家分享的《Python利用共享经济提升性能》一文吧。以下文章来源:微信♂Python猫作者:豌豆花猫下大家可能知道,Python为了提高内存利用效率,采用了一套共享对象的内存分配策略。比如对于数值较小的number对象([-5,256])、boolean对象、None对象、较短的string对象(通常为20)等,字面上的equal对象其实就是同一个对象。共享内存地址示例a=100b=100s="python_cat"t="python_cat"id(a)==id(b)#Result:Trueid(s)==id(t)#Result:True我很早在我写文章《Python中的“特权种族”是什么?》的时候,这些对象统称为“特权种族”,是Python在内存管理机制上使用的优化技术。不久前,我还写了一篇文章《Python 内存分配时的小秘密》,里面也介绍了内存管理的技巧。这两篇文章不同的是,老篇文章主要涉及内存共享和对象驻留机制,而新篇文章介绍了内存分配、动态扩展和内存回收的相关机制。它们让我不由自主地想到两个词:共享经济和供需平衡。如果你还没有读过那两篇文章,我强烈建议你先把它们读回来,然后看看我的联想是否有道理:那些类型的特权种族对象实际上是在共享内存,看似不同的对象实际上是在回收;至于供需平衡,很容易理解。创建某些对象时,根据预期需求分配内存,扩容时灵活调整,实现供需平衡。透过现象看本质,Python可以很有趣。然而,Python的有趣特性并不止于此。本文将继续分享另一种内存管理机制。某种程度上实现了共享经济与供需平衡的融合,从中我们可以揭示出Python的另一个身份。...1。不可变对象的共享经济上面列出的“特权种族”都是不可变对象(而“供需平衡”主要发生在可变对象中),对于这些不可变对象,当有多种用途时,共享一个对象似乎是一个不错的选择优化。我曾经有一个猜测:Python的不可变对象可能是一个特权种族。我没有试图完全证明它,这篇文章只是想考察一种不可变对象:元组。它是一个不可变的对象,那么,有共享对象的机制吗?让我们将它与列表进行比较:空对象之间的区别a=[]b=[]c=()d=()print(id(a)==id(b))#Result:Falseprint(id(c)==id(d))#Result:True可见两个空列表是不同的对象,两个空元组其实是同一个对象。这至少说明内存中只有一个空元组,属于已经提到的特权种族。将实验扩展到集合和字典这些可变对象,你会发现结果和列表一样,有多个副本,即不是特权种族。我不会举例。从上面的实验结果可以得出两个问题,但是都偏离了本文的主题,我不打算深入分析,只是简单罗列一下:除了空元组,还有哪些元组是“特权种族”“?(PS:考虑到元素的个数,类型,元素本身的大小,小规模的实验我还没有发现。那么,空元组是不是唯一的?)编译期和runtime,之前写的strings(《Intern机制的软肋》)的intern机制也分析过了。(PS:print(id([])==id([])),结果为True,区别于前面先赋值再比较的例子。)2.可变对象的共享经济空元组体现了共享经济,但由于是不可变对象,没有动态扩容,只能反映极小的供需平衡。相比之下,榜单等可变对象充分代表了供求平衡,但似乎没有办法体现共享经济。例如,让我们将列表想象成一个自动递增的玻璃杯(毕竟它是某种容器),并将其元素想象成不同种类的液体(水、可乐、酒……)。那么,我们的问题是:两个杯子是否可以作为一个对象共享?或者,可以分享那个杯子吗?这样可以节省内存(如小秘密:“空杯子”占用大量内存一文所示),提高效率。对于第一个问题,答案是否定的,省略验证过程。对于第二个问题,在上一节中,我们验证了两个空杯子(也就是空列表),答案同样是否定的。不过,第二个问题还有其他的可能!我们换个实验方法:实验版本:Python3.6.1a=[[]foriinrange(4)]print(id(a))foriinrange(len(a)):print(f'{i}--{id(a[i])}')#a[i]=1#PS:可以去掉注释再执行,结果顺序不同delaprint("afterdel")b=[[]foriinrange(4)]print(id(b))foriinrange(len(b)):print(f'{i}--{id(b[i])}')以上codeIndifferentenvironments,theexecutionresultsmayvary.我执行的一次结果如下:20129093956560?--?20129093952721?--?20129094064722?--?20129093952083?--?2012909395144after?del20129093956560?--?20129093952721?--?20129094064722?--?20129093952083?--?2012909395144分析结果可知:列表对象在被回收之后,并不会彻底清除,它的内存地址会传递给新创建的链表,即新创建的链表实际上共享旧链表的内存地址!结合前面的例子,我们可以说,先后静态创建的两个列表会分配到不同的内存地址,但是动态回收后,先后创建的列表可能在同一个内存地址!(注意:我这里说“可能”,因为在创建新列表之前,如果其他地方正在创建列表,后者可能会趁机。)扩展到其他基本可变对象,例如集合和字典,也有同样的共享策略,其目的很明显:回收这些对象的“残余”,避免内存碎片,提高执行性能。分享一个杯子比重新制作一个杯子更高效、更方便,对吧?在实现这种机制时,Python解释器使用一个名为free_list的全局变量。它的工作原理是:在创建新对象时,会检查free_list中是否有可用的对象。析构时,检查free_list中是否还有剩余空间,如果free_list中存有某种类型的对象,则只保留“body”,清空里面的所有元素(即,只分享杯子,不分享杯子里的东西)。来源:https://dwz.cn/QWD6RxOx好了,现在我们可以说,列表、集合、字典等可变对象并不是上面说的特权种族,而是隐藏在它们背后的回收共享思想,这是环环相扣的。Python解释器在内存管理上真是煞费苦心。它对那些司空见惯的基本对象施加了很多小魔力。在我们毫无察觉的情况下,它们有条不紊地运作着。不要感叹它的精致。Python堪称细心的“经济学家”。回顾全文,最后做一个总结:较小的数字、较短的字符串、布尔值、空元组等不可变对象具有提高内存使用效率的“共享经济”机制。字典等可变对象具有预分配和过度分配等“供需平衡”机制,提高了内存分配效率。列表等对象也有共享的“容器外壳”机制,回收闲置资源,全面改进程序。表现