日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python使用函数可以减少内存吗_如何将Python内存占用缩小20倍?

發(fā)布時(shí)間:2025/3/21 python 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python使用函数可以减少内存吗_如何将Python内存占用缩小20倍? 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

當(dāng)程序執(zhí)行過程中RAM中有大量對(duì)象處于活動(dòng)狀態(tài)時(shí),可能會(huì)出現(xiàn)內(nèi)存問題,特別是在對(duì)可用內(nèi)存總量有限制的情況下。

下面概述了一些減小對(duì)象大小的方法,這些方法可以顯著減少純Python程序所需的RAM數(shù)量。

注: 這是我原帖子的英文版本(原帖子是用俄文寫的)。(https://habr.com/ru/post/455722/ )

為了簡單起見,我們將考慮用Python中的結(jié)構(gòu)來表示坐標(biāo)為x、y、z的點(diǎn),并通過名稱來訪問坐標(biāo)值。

Dict

在小程序中,特別是在腳本中,使用內(nèi)置的dict來表示結(jié)構(gòu)信息是非常簡單方便的:

隨著Python 3.6中使用一組有序鍵的更緊湊實(shí)現(xiàn)方式的出現(xiàn),dict變得更有吸引力。但是,讓我們看看它在RAM中的內(nèi)存大小:

它需要大量內(nèi)存,特別是當(dāng)你突然需要?jiǎng)?chuàng)建大量實(shí)例時(shí):

類實(shí)例

對(duì)于那些喜歡將所有東西放置在類中的人來說,最好將結(jié)構(gòu)定義為一個(gè)可以通過屬性名訪問的類,:

類實(shí)例的結(jié)構(gòu)很有趣:

這里的__weakref__是對(duì)這個(gè)對(duì)象的所謂弱引用列表的一個(gè)引用,__dict__字段是對(duì)類實(shí)例字典的引用,它包含實(shí)例屬性的值(注意64位的引用平臺(tái)會(huì)占用8個(gè)字節(jié))。從Python 3.3開始,共享空間用于在字典中存儲(chǔ)類的所有實(shí)例的鍵。這減少了RAM中實(shí)例堆棧的大小:

因此,大量的類實(shí)例占用的內(nèi)存比一個(gè)普通字典(dict)占用的要小:

很容易看出,由于實(shí)例字典的大小,RAM中實(shí)例的大小仍然很大。

帶有__slots__的類實(shí)例

通過消除 __dict__和__weakref__,可以顯著減小RAM中的類實(shí)例的大小。這通過一個(gè)帶有__slots__的小“技巧”是可能實(shí)現(xiàn)的:

RAM中的對(duì)象大小明顯變小了:

在類定義中使用__slots__可以顯著減少大量實(shí)例對(duì)內(nèi)存空間的占用:

目前,這是大幅度減少RAM中類實(shí)例的內(nèi)存占用的主要方法。

這是因?yàn)樵趦?nèi)存中,對(duì)象引用會(huì)緊跟標(biāo)題之后被存儲(chǔ)在內(nèi)存中——屬性值,并通過類字典中的特殊描述符來訪問它們:

要自動(dòng)化使用 __slots__創(chuàng)建一個(gè)類的過程,有一個(gè)庫[namedlist] (https://pypi.org/project/namedlist )可以使用。namedlist.namedlist函數(shù)會(huì)創(chuàng)建一個(gè)帶有__slots__的類:

另一個(gè)包[attrs] (https://pypi.org/project/attrs )允許你使用和不使用__slots__自動(dòng)創(chuàng)建類。

元組

Python還有一個(gè)內(nèi)置的類型tuple(元組),用于表示不可變的數(shù)據(jù)結(jié)構(gòu)。一個(gè)元組是一個(gè)固定的結(jié)構(gòu)或記錄,但沒有字段名。對(duì)于字段訪問,使用的是字段索引。元組字段在元組實(shí)例創(chuàng)建時(shí)就一次性與值對(duì)象相關(guān)聯(lián):

元組的實(shí)例是相當(dāng)簡潔的:

它們?cè)趦?nèi)存中占用的字節(jié)比使用__slots__的類實(shí)例要多8個(gè)字節(jié),因?yàn)閮?nèi)存中的元組跟蹤也包含許多字段:

Namedtuple(命名元組)

由于元組使用的非常廣泛,某天有人可能會(huì)提交一個(gè)通過名稱訪問字段的請(qǐng)求。這個(gè)請(qǐng)求的答案是collections.namedtuple模塊。

namedtuple函數(shù)的目的是自動(dòng)生成這樣的類:

它會(huì)創(chuàng)建一個(gè)元組子類,其中定義了用于按名稱訪問字段的描述符。在我們的例子中,它看起來是這樣的:

這些類的所有實(shí)例都具有與元組相同的內(nèi)存占用量。大量的實(shí)例會(huì)占用更大的內(nèi)存空間:

Recordclass: 沒有循環(huán)GC的可變namedtuple

由于tuple和相應(yīng)的namedtuple類會(huì)生成不可變對(duì)象,因此,ob.x屬性就不能再與另一個(gè)值對(duì)象相關(guān)聯(lián)了,對(duì)可變namedtuple變體的請(qǐng)求已經(jīng)出現(xiàn)了。由于Python中沒有與支持賦值的元組相同的內(nèi)置類型,因此,開發(fā)者們創(chuàng)建了許多選項(xiàng)。我們將關(guān)注[recordclass] (https://pypi.org/project/recordclass ),它的評(píng)級(jí)為[stackoverflow] (https://stackoverflow.com/questions/29290359/ exists -of-mutable-name - tuplein -python / 29419745 )。此外,與類元組對(duì)象的大小相比,它還可以用來減小RAM中對(duì)象的大小。

包recordclass引入了recordclass.mutabletuple類型,它幾乎與tuple相同,但它支持賦值。在此基礎(chǔ)上,創(chuàng)建的子類幾乎與namedtuple完全相同,但它支持將新值賦給字段(不需要?jiǎng)?chuàng)建新的實(shí)例)。recordclass函數(shù)與namedtuple函數(shù)一樣,允許你自動(dòng)創(chuàng)建這些類:

只有在沒有PyGC_Head的情況下,類實(shí)例才具有與tuple相同的結(jié)構(gòu):

默認(rèn)情況下,recordclass函數(shù)會(huì)創(chuàng)建一個(gè)不參與循環(huán)垃圾回收機(jī)制的類。通常,namedtuple和recordclass用于生成表示記錄或簡單(非遞歸)數(shù)據(jù)結(jié)構(gòu)的類。在Python中正確使用它們就不會(huì)生成循環(huán)引用。出于這個(gè)原因, 在recordclass生成的類實(shí)例后面 ,默認(rèn)情況下,PyGC_Head 部分會(huì)被排除在外, 這對(duì)支持循環(huán)垃圾回收機(jī)制(更準(zhǔn)確地說:在與創(chuàng)建的類相關(guān)聯(lián)的PyTypeObject結(jié)構(gòu)中,默認(rèn)情況下,flag字段中的Py_TPFLAGS_HAVE_GC是沒有設(shè)置的)的類來說是必要的。

大量實(shí)例的內(nèi)存占用量比使用了__slots__的類的實(shí)例要小:

Dataobject

recordclass庫中提出的另一個(gè)解決方案是基于這樣的思想:在內(nèi)存中使用與帶有__slots__的類實(shí)例相同的存儲(chǔ)結(jié)構(gòu),但不參與循環(huán)垃圾回收機(jī)制。這些類是使用recordclass.make_dataclass數(shù)生成的:

默認(rèn)情況下,以這種方式創(chuàng)建的類將創(chuàng)建可變實(shí)例。

另一種方法——使用繼承自recordclass.dataobject的類聲明:

以這種方式創(chuàng)建的類將創(chuàng)建不參與循環(huán)垃圾回收機(jī)制的實(shí)例。內(nèi)存中實(shí)例的結(jié)構(gòu)與使用__slots__的情況相同,但是沒有PyGC_Head:

為了訪問字段,還可以使用特殊的描述符通過它從對(duì)象開始的偏移量來訪問,這些偏移量位于類字典中:

大量實(shí)例內(nèi)存占用量的大小在CPython中可能是最小的:

Cython

還有一種基于使用[Cython] (https://cython.org )的方法。它的優(yōu)點(diǎn)是字段可以接受C語言原子類型的值。自動(dòng)創(chuàng)建用于從純Python中來訪問字段的描述符。例如:

在這種情況下,實(shí)例的內(nèi)存占用更小:

內(nèi)存中的實(shí)例跟蹤的結(jié)構(gòu)如下:

大量副本的占用空間要小一些:

但是,請(qǐng)記住,當(dāng)你從Python代碼訪問時(shí),每次都會(huì)執(zhí)行從int到Python對(duì)象的轉(zhuǎn)換,反之亦然。

Numpy

對(duì)大量數(shù)據(jù)使用多維數(shù)組或記錄數(shù)組會(huì)增加內(nèi)存占用。但是,為了在純Python中進(jìn)行有效的處理,你應(yīng)該使用那些主要使用了numpy包中的函數(shù)的處理方法。

使用函數(shù)創(chuàng)建一個(gè)由N個(gè)元素組成的數(shù)組,并將其初始化為0:

內(nèi)存中數(shù)組的大小是可能的最小值:

正常訪問數(shù)組元素和行需要將Python對(duì)象轉(zhuǎn)換為C中的 int值,反之亦然。提取單個(gè)行會(huì)創(chuàng)建一個(gè)包含單個(gè)元素的數(shù)組。它的追蹤就不再那么簡單了:

因此,如上所述,在Python代碼中,有必要使用numpy包中的函數(shù)來處理數(shù)組。

結(jié)論

通過一個(gè)清晰而簡單的示例,可以驗(yàn)證由開發(fā)人員和用戶組成的Python編程語言(CPython)社區(qū)確實(shí)有可能顯著減少對(duì)象使用的內(nèi)存量。

英文原文:https://habr.com/en/post/458518/

譯者:Nothing

總結(jié)

以上是生活随笔為你收集整理的python使用函数可以减少内存吗_如何将Python内存占用缩小20倍?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。